summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_listener_2d.cpp (renamed from scene/2d/listener_2d.cpp)32
-rw-r--r--scene/2d/audio_listener_2d.h (renamed from scene/2d/listener_2d.h)6
-rw-r--r--scene/2d/audio_stream_player_2d.cpp4
-rw-r--r--scene/2d/camera_2d.cpp2
-rw-r--r--scene/2d/collision_polygon_2d.cpp2
-rw-r--r--scene/2d/collision_shape_2d.cpp2
-rw-r--r--scene/2d/cpu_particles_2d.cpp4
-rw-r--r--scene/2d/navigation_region_2d.cpp2
-rw-r--r--scene/2d/parallax_layer.cpp4
-rw-r--r--scene/2d/physical_bone_2d.cpp24
-rw-r--r--scene/2d/physical_bone_2d.h4
-rw-r--r--scene/2d/physics_body_2d.cpp365
-rw-r--r--scene/2d/physics_body_2d.h46
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp86
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/audio_listener_3d.cpp (renamed from scene/3d/listener_3d.cpp)65
-rw-r--r--scene/3d/audio_listener_3d.h (renamed from scene/3d/listener_3d.h)13
-rw-r--r--scene/3d/audio_stream_player_3d.cpp20
-rw-r--r--scene/3d/audio_stream_player_3d.h11
-rw-r--r--scene/3d/bone_attachment_3d.cpp4
-rw-r--r--scene/3d/camera_3d.cpp4
-rw-r--r--scene/3d/camera_3d.h2
-rw-r--r--scene/3d/collision_polygon_3d.cpp2
-rw-r--r--scene/3d/collision_shape_3d.cpp9
-rw-r--r--scene/3d/gpu_particles_3d.cpp2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp4
-rw-r--r--scene/3d/light_3d.cpp4
-rw-r--r--scene/3d/light_3d.h2
-rw-r--r--scene/3d/lightmap_gi.cpp4
-rw-r--r--scene/3d/physics_body_3d.cpp1163
-rw-r--r--scene/3d/physics_body_3d.h240
-rw-r--r--scene/3d/skeleton_3d.cpp1
-rw-r--r--scene/3d/skeleton_ik_3d.cpp4
-rw-r--r--scene/3d/soft_dynamic_body_3d.cpp (renamed from scene/3d/soft_body_3d.cpp)244
-rw-r--r--scene/3d/soft_dynamic_body_3d.h (renamed from scene/3d/soft_body_3d.h)32
-rw-r--r--scene/3d/vehicle_body_3d.cpp8
-rw-r--r--scene/3d/vehicle_body_3d.h4
-rw-r--r--scene/3d/voxelizer.cpp8
-rw-r--r--scene/animation/SCsub3
-rw-r--r--scene/animation/animation_blend_tree.cpp15
-rw-r--r--scene/animation/animation_player.cpp3
-rw-r--r--scene/animation/animation_tree.cpp2
-rw-r--r--scene/animation/easing_equations.h405
-rw-r--r--scene/animation/tween.cpp36
-rw-r--r--scene/animation/tween.h4
-rw-r--r--scene/gui/code_edit.cpp33
-rw-r--r--scene/gui/code_edit.h2
-rw-r--r--scene/gui/color_picker.cpp16
-rw-r--r--scene/gui/container.cpp5
-rw-r--r--scene/gui/graph_edit.cpp21
-rw-r--r--scene/gui/graph_node.cpp26
-rw-r--r--scene/gui/graph_node.h5
-rw-r--r--scene/gui/label.cpp102
-rw-r--r--scene/gui/line_edit.cpp13
-rw-r--r--scene/gui/line_edit.h4
-rw-r--r--scene/gui/menu_button.cpp12
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/popup.cpp8
-rw-r--r--scene/gui/rich_text_effect.cpp8
-rw-r--r--scene/gui/rich_text_effect.h14
-rw-r--r--scene/gui/rich_text_label.cpp225
-rw-r--r--scene/gui/rich_text_label.h21
-rw-r--r--scene/gui/scroll_bar.cpp2
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/spin_box.cpp31
-rw-r--r--scene/gui/spin_box.h6
-rw-r--r--scene/gui/tab_container.cpp8
-rw-r--r--scene/gui/tabs.cpp32
-rw-r--r--scene/gui/text_edit.cpp18
-rw-r--r--scene/gui/texture_progress_bar.cpp5
-rw-r--r--scene/gui/tree.cpp155
-rw-r--r--scene/gui/tree.h3
-rw-r--r--scene/main/node.cpp17
-rw-r--r--scene/main/scene_tree.cpp1
-rw-r--r--scene/main/viewport.cpp117
-rw-r--r--scene/main/viewport.h42
-rw-r--r--scene/register_scene_types.cpp35
-rw-r--r--scene/resources/bit_map.cpp2
-rw-r--r--scene/resources/canvas_item_material.cpp3
-rw-r--r--scene/resources/canvas_item_material.h1
-rw-r--r--scene/resources/default_theme/default_theme.cpp8
-rw-r--r--scene/resources/font.cpp67
-rw-r--r--scene/resources/immediate_mesh.cpp3
-rw-r--r--scene/resources/immediate_mesh.h1
-rw-r--r--scene/resources/material.cpp9
-rw-r--r--scene/resources/material.h1
-rw-r--r--scene/resources/mesh.cpp103
-rw-r--r--scene/resources/mesh.h5
-rw-r--r--scene/resources/packed_scene.cpp3
-rw-r--r--scene/resources/particles_material.cpp3
-rw-r--r--scene/resources/particles_material.h1
-rw-r--r--scene/resources/primitive_meshes.cpp8
-rw-r--r--scene/resources/primitive_meshes.h2
-rw-r--r--scene/resources/skeleton_modification_2d.cpp42
-rw-r--r--scene/resources/skeleton_modification_2d_fabrik.cpp4
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d.cpp40
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.cpp4
-rw-r--r--scene/resources/surface_tool.cpp1
-rw-r--r--scene/resources/texture.cpp8
-rw-r--r--scene/resources/texture.h2
-rw-r--r--scene/resources/tile_set.cpp423
-rw-r--r--scene/resources/tile_set.h36
-rw-r--r--scene/resources/world_boundary_shape_2d.cpp (renamed from scene/resources/world_margin_shape_2d.cpp)36
-rw-r--r--scene/resources/world_boundary_shape_2d.h (renamed from scene/resources/world_margin_shape_2d.h)16
-rw-r--r--scene/resources/world_boundary_shape_3d.cpp (renamed from scene/resources/world_margin_shape_3d.cpp)22
-rw-r--r--scene/resources/world_boundary_shape_3d.h (renamed from scene/resources/world_margin_shape_3d.h)18
-rw-r--r--scene/scene_string_names.cpp3
-rw-r--r--scene/scene_string_names.h3
110 files changed, 3185 insertions, 1591 deletions
diff --git a/scene/2d/listener_2d.cpp b/scene/2d/audio_listener_2d.cpp
index 444f05f2b1..f16e359a1d 100644
--- a/scene/2d/listener_2d.cpp
+++ b/scene/2d/audio_listener_2d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* listener_2d.cpp */
+/* audio_listener_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "listener_2d.h"
+#include "audio_listener_2d.h"
-bool Listener2D::_set(const StringName &p_name, const Variant &p_value) {
+bool AudioListener2D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "current") {
if (p_value.operator bool()) {
make_current();
@@ -43,7 +43,7 @@ bool Listener2D::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
-bool Listener2D::_get(const StringName &p_name, Variant &r_ret) const {
+bool AudioListener2D::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "current") {
if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
r_ret = current;
@@ -56,11 +56,11 @@ bool Listener2D::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-void Listener2D::_get_property_list(List<PropertyInfo> *p_list) const {
+void AudioListener2D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
}
-void Listener2D::_notification(int p_what) {
+void AudioListener2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
if (!get_tree()->is_node_being_edited(this) && current) {
@@ -80,33 +80,33 @@ void Listener2D::_notification(int p_what) {
}
}
-void Listener2D::make_current() {
+void AudioListener2D::make_current() {
current = true;
if (!is_inside_tree()) {
return;
}
- get_viewport()->_listener_2d_set(this);
+ get_viewport()->_audio_listener_2d_set(this);
}
-void Listener2D::clear_current() {
+void AudioListener2D::clear_current() {
current = false;
if (!is_inside_tree()) {
return;
}
- get_viewport()->_listener_2d_remove(this);
+ get_viewport()->_audio_listener_2d_remove(this);
}
-bool Listener2D::is_current() const {
+bool AudioListener2D::is_current() const {
if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
- return get_viewport()->get_listener_2d() == this;
+ return get_viewport()->get_audio_listener_2d() == this;
} else {
return current;
}
return false;
}
-void Listener2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("make_current"), &Listener2D::make_current);
- ClassDB::bind_method(D_METHOD("clear_current"), &Listener2D::clear_current);
- ClassDB::bind_method(D_METHOD("is_current"), &Listener2D::is_current);
+void AudioListener2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("make_current"), &AudioListener2D::make_current);
+ ClassDB::bind_method(D_METHOD("clear_current"), &AudioListener2D::clear_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &AudioListener2D::is_current);
}
diff --git a/scene/2d/listener_2d.h b/scene/2d/audio_listener_2d.h
index 0289a8087d..875887acc6 100644
--- a/scene/2d/listener_2d.h
+++ b/scene/2d/audio_listener_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* listener_2d.h */
+/* audio_listener_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -34,8 +34,8 @@
#include "scene/2d/node_2d.h"
#include "scene/main/window.h"
-class Listener2D : public Node2D {
- GDCLASS(Listener2D, Node2D);
+class AudioListener2D : public Node2D {
+ GDCLASS(AudioListener2D, Node2D);
private:
bool current = false;
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 8401909384..bddc342c1a 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -31,7 +31,7 @@
#include "audio_stream_player_2d.h"
#include "scene/2d/area_2d.h"
-#include "scene/2d/listener_2d.h"
+#include "scene/2d/audio_listener_2d.h"
#include "scene/main/window.h"
void AudioStreamPlayer2D::_notification(int p_what) {
@@ -156,7 +156,7 @@ void AudioStreamPlayer2D::_update_panning() {
Vector2 relative_to_listener;
//screen in global is used for attenuation
- Listener2D *listener = vp->get_listener_2d();
+ AudioListener2D *listener = vp->get_audio_listener_2d();
if (listener) {
listener_in_global = listener->get_global_position();
relative_to_listener = global_pos - listener_in_global;
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index bf91ce8e65..8195d98f55 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -198,7 +198,7 @@ Transform2D Camera2D::get_camera_transform() {
screen_rect.position += offset;
}
- camera_screen_center = screen_rect.position + screen_rect.size * 0.5;
+ camera_screen_center = screen_rect.get_center();
Transform2D xform;
xform.scale_basis(zoom);
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 8c8a292ad7..271a4da705 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -243,7 +243,7 @@ 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, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
+ 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."));
}
int polygon_count = polygon.size();
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index d52795f0d5..54cb851216 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -175,7 +175,7 @@ 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, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
+ 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."));
}
if (!shape.is_valid()) {
warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index b836497627..bf26ec1f20 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -155,7 +155,7 @@ void CPUParticles2D::_update_mesh_texture() {
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 + Vector2(tex_size.x, tex_size.y));
+ vertices.push_back(-tex_size * 0.5 + tex_size);
vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y));
Vector<Vector2> uvs;
AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture);
@@ -727,7 +727,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
p.hue_rot_rand = Math::randf();
p.anim_offset_rand = Math::randf();
- real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
+ 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());
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 72ea6541e3..cbf0d50c4e 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -464,7 +464,7 @@ void NavigationRegion2D::_notification(int p_what) {
draw_line(a, b, doors_color);
// Draw a circle to illustrate the margins.
- real_t angle = (b - a).angle();
+ real_t angle = b.angle_to_point(a);
draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color);
draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color);
}
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 1fe6a4a4b8..67e35cc7a3 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -100,6 +100,10 @@ void ParallaxLayer::_notification(int p_what) {
_update_mirroring();
} break;
case NOTIFICATION_EXIT_TREE: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ break;
+ }
+
set_position(orig_offset);
set_scale(orig_scale);
} break;
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
index d547914e16..48817679bc 100644
--- a/scene/2d/physical_bone_2d.cpp
+++ b/scene/2d/physical_bone_2d.cpp
@@ -33,7 +33,7 @@
void PhysicalBone2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- // Position the RigidBody in the correct position.
+ // Position the RigidDynamicBody in the correct position.
if (follow_bone_when_simulating) {
_position_at_bone2d();
}
@@ -150,27 +150,15 @@ void PhysicalBone2D::_start_physics_simulation() {
return;
}
- // Reset to Bone2D position
+ // Reset to Bone2D position.
_position_at_bone2d();
- // Apply the layers and masks
+ // Apply the layers and masks.
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- // Apply the correct mode
- RigidBody2D::Mode rigid_mode = get_mode();
- if (rigid_mode == RigidBody2D::MODE_STATIC) {
- set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
- } else if (rigid_mode == RigidBody2D::MODE_DYNAMIC) {
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
- } else if (rigid_mode == RigidBody2D::MODE_KINEMATIC) {
- set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
- } else if (rigid_mode == RigidBody2D::MODE_DYNAMIC_LOCKED) {
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED);
- } else {
- // Default to Dynamic.
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
- }
+ // Apply the correct mode.
+ _apply_body_mode();
_internal_simulate_physics = true;
set_physics_process_internal(true);
@@ -295,7 +283,7 @@ void PhysicalBone2D::_bind_methods() {
}
PhysicalBone2D::PhysicalBone2D() {
- // Stop the RigidBody from executing its force integration.
+ // Stop the RigidDynamicBody from executing its force integration.
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h
index 46a2772bad..a250d0aadd 100644
--- a/scene/2d/physical_bone_2d.h
+++ b/scene/2d/physical_bone_2d.h
@@ -36,8 +36,8 @@
#include "scene/2d/skeleton_2d.h"
-class PhysicalBone2D : public RigidBody2D {
- GDCLASS(PhysicalBone2D, RigidBody2D);
+class PhysicalBone2D : public RigidDynamicBody2D {
+ GDCLASS(PhysicalBone2D, RigidDynamicBody2D);
protected:
void _notification(int p_what);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 30f012c7aa..c07a999588 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -34,8 +34,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
+ 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("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -57,8 +57,12 @@ PhysicsBody2D::~PhysicsBody2D() {
Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionResult result;
- if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
- if (motion_cache.is_null()) {
+ // 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();
+
+ if (move_and_collide(p_motion * delta, result, p_margin, p_test_only)) {
+ // Create a new instance when the cached reference is invalid or still in use in script.
+ if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
motion_cache.instantiate();
motion_cache->owner = this;
}
@@ -132,7 +136,10 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
+ // 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();
+
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r);
}
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
@@ -309,7 +316,7 @@ AnimatableBody2D::AnimatableBody2D() :
_update_kinematic_motion();
}
-void RigidBody2D::_body_enter_tree(ObjectID p_id) {
+void RigidDynamicBody2D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -331,7 +338,7 @@ void RigidBody2D::_body_enter_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidBody2D::_body_exit_tree(ObjectID p_id) {
+void RigidDynamicBody2D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -352,7 +359,7 @@ void RigidBody2D::_body_exit_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -371,8 +378,8 @@ void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
//E->get().rc=0;
E->get().in_scene = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree), make_binds(objid));
+ 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) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -400,8 +407,8 @@ void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
if (E->get().shapes.is_empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree));
+ 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));
if (in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
@@ -415,21 +422,21 @@ void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
}
}
-struct _RigidBody2DInOut {
+struct _RigidDynamicBody2DInOut {
RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
};
-void RigidBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
- RigidBody2D *body = (RigidBody2D *)p_instance;
+void RigidDynamicBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
+ RigidDynamicBody2D *body = (RigidDynamicBody2D *)p_instance;
body->_body_state_changed(p_state);
}
-void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
+void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop)
- if (mode != MODE_KINEMATIC) {
+ if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) {
set_global_transform(p_state->get_transform());
}
@@ -457,9 +464,9 @@ void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
}
}
- _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBody2DInOut));
+ _RigidDynamicBody2DInOut *toadd = (_RigidDynamicBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidDynamicBody2DInOut));
int toadd_count = 0; //state->get_contact_count();
- RigidBody2D_RemoveAction *toremove = (RigidBody2D_RemoveAction *)alloca(rc * sizeof(RigidBody2D_RemoveAction));
+ RigidDynamicBody2D_RemoveAction *toremove = (RigidDynamicBody2D_RemoveAction *)alloca(rc * sizeof(RigidDynamicBody2D_RemoveAction));
int toremove_count = 0;
//put the ones to add
@@ -523,52 +530,83 @@ void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
}
}
-void RigidBody2D::set_mode(Mode p_mode) {
- mode = p_mode;
- switch (p_mode) {
- case MODE_DYNAMIC: {
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
- } break;
- case MODE_STATIC: {
- set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
+void RigidDynamicBody2D::_apply_body_mode() {
+ if (freeze) {
+ switch (freeze_mode) {
+ case FREEZE_MODE_STATIC: {
+ set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
+ } break;
+ case FREEZE_MODE_KINEMATIC: {
+ set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
+ } break;
+ }
+ } else if (lock_rotation) {
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR);
+ } else {
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
+ }
+}
- } break;
- case MODE_KINEMATIC: {
- set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
+void RigidDynamicBody2D::set_lock_rotation_enabled(bool p_lock_rotation) {
+ if (p_lock_rotation == lock_rotation) {
+ return;
+ }
- } break;
- case MODE_DYNAMIC_LOCKED: {
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED);
+ lock_rotation = p_lock_rotation;
+ _apply_body_mode();
+}
- } break;
+bool RigidDynamicBody2D::is_lock_rotation_enabled() const {
+ return lock_rotation;
+}
+
+void RigidDynamicBody2D::set_freeze_enabled(bool p_freeze) {
+ if (p_freeze == freeze) {
+ return;
}
+
+ freeze = p_freeze;
+ _apply_body_mode();
}
-RigidBody2D::Mode RigidBody2D::get_mode() const {
- return mode;
+bool RigidDynamicBody2D::is_freeze_enabled() const {
+ return freeze;
}
-void RigidBody2D::set_mass(real_t p_mass) {
+void RigidDynamicBody2D::set_freeze_mode(FreezeMode p_freeze_mode) {
+ if (p_freeze_mode == freeze_mode) {
+ return;
+ }
+
+ freeze_mode = p_freeze_mode;
+ _apply_body_mode();
+}
+
+RigidDynamicBody2D::FreezeMode RigidDynamicBody2D::get_freeze_mode() const {
+ return freeze_mode;
+}
+
+void RigidDynamicBody2D::set_mass(real_t p_mass) {
ERR_FAIL_COND(p_mass <= 0);
mass = p_mass;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_MASS, mass);
}
-real_t RigidBody2D::get_mass() const {
+real_t RigidDynamicBody2D::get_mass() const {
return mass;
}
-void RigidBody2D::set_inertia(real_t p_inertia) {
+void RigidDynamicBody2D::set_inertia(real_t p_inertia) {
ERR_FAIL_COND(p_inertia < 0);
inertia = p_inertia;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia);
}
-real_t RigidBody2D::get_inertia() const {
+real_t RigidDynamicBody2D::get_inertia() const {
return inertia;
}
-void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
+void RigidDynamicBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
if (center_of_mass_mode == p_mode) {
return;
}
@@ -590,11 +628,11 @@ void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
}
}
-RigidBody2D::CenterOfMassMode RigidBody2D::get_center_of_mass_mode() const {
+RigidDynamicBody2D::CenterOfMassMode RigidDynamicBody2D::get_center_of_mass_mode() const {
return center_of_mass_mode;
}
-void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
+void RigidDynamicBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
if (center_of_mass == p_center_of_mass) {
return;
}
@@ -605,84 +643,84 @@ void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
}
-const Vector2 &RigidBody2D::get_center_of_mass() const {
+const Vector2 &RigidDynamicBody2D::get_center_of_mass() const {
return center_of_mass;
}
-void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+void RigidDynamicBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody2D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody2D::_reload_physics_characteristics));
}
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody2D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
-Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const {
+Ref<PhysicsMaterial> RigidDynamicBody2D::get_physics_material_override() const {
return physics_material_override;
}
-void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) {
+void RigidDynamicBody2D::set_gravity_scale(real_t p_gravity_scale) {
gravity_scale = p_gravity_scale;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
}
-real_t RigidBody2D::get_gravity_scale() const {
+real_t RigidDynamicBody2D::get_gravity_scale() const {
return gravity_scale;
}
-void RigidBody2D::set_linear_damp(real_t p_linear_damp) {
+void RigidDynamicBody2D::set_linear_damp(real_t p_linear_damp) {
ERR_FAIL_COND(p_linear_damp < -1);
linear_damp = p_linear_damp;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP, linear_damp);
}
-real_t RigidBody2D::get_linear_damp() const {
+real_t RigidDynamicBody2D::get_linear_damp() const {
return linear_damp;
}
-void RigidBody2D::set_angular_damp(real_t p_angular_damp) {
+void RigidDynamicBody2D::set_angular_damp(real_t p_angular_damp) {
ERR_FAIL_COND(p_angular_damp < -1);
angular_damp = p_angular_damp;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
}
-real_t RigidBody2D::get_angular_damp() const {
+real_t RigidDynamicBody2D::get_angular_damp() const {
return angular_damp;
}
-void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) {
+void RigidDynamicBody2D::set_axis_velocity(const Vector2 &p_axis) {
Vector2 axis = p_axis.normalized();
linear_velocity -= axis * axis.dot(linear_velocity);
linear_velocity += p_axis;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) {
+void RigidDynamicBody2D::set_linear_velocity(const Vector2 &p_velocity) {
linear_velocity = p_velocity;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-Vector2 RigidBody2D::get_linear_velocity() const {
+Vector2 RigidDynamicBody2D::get_linear_velocity() const {
return linear_velocity;
}
-void RigidBody2D::set_angular_velocity(real_t p_velocity) {
+void RigidDynamicBody2D::set_angular_velocity(real_t p_velocity) {
angular_velocity = p_velocity;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
-real_t RigidBody2D::get_angular_velocity() const {
+real_t RigidDynamicBody2D::get_angular_velocity() const {
return angular_velocity;
}
-void RigidBody2D::set_use_custom_integrator(bool p_enable) {
+void RigidDynamicBody2D::set_use_custom_integrator(bool p_enable) {
if (custom_integrator == p_enable) {
return;
}
@@ -691,87 +729,87 @@ void RigidBody2D::set_use_custom_integrator(bool p_enable) {
PhysicsServer2D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
}
-bool RigidBody2D::is_using_custom_integrator() {
+bool RigidDynamicBody2D::is_using_custom_integrator() {
return custom_integrator;
}
-void RigidBody2D::set_sleeping(bool p_sleeping) {
+void RigidDynamicBody2D::set_sleeping(bool p_sleeping) {
sleeping = p_sleeping;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_SLEEPING, sleeping);
}
-void RigidBody2D::set_can_sleep(bool p_active) {
+void RigidDynamicBody2D::set_can_sleep(bool p_active) {
can_sleep = p_active;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_CAN_SLEEP, p_active);
}
-bool RigidBody2D::is_able_to_sleep() const {
+bool RigidDynamicBody2D::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidBody2D::is_sleeping() const {
+bool RigidDynamicBody2D::is_sleeping() const {
return sleeping;
}
-void RigidBody2D::set_max_contacts_reported(int p_amount) {
+void RigidDynamicBody2D::set_max_contacts_reported(int p_amount) {
max_contacts_reported = p_amount;
PhysicsServer2D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
-int RigidBody2D::get_max_contacts_reported() const {
+int RigidDynamicBody2D::get_max_contacts_reported() const {
return max_contacts_reported;
}
-void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) {
+void RigidDynamicBody2D::apply_central_impulse(const Vector2 &p_impulse) {
PhysicsServer2D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
}
-void RigidBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) {
+void RigidDynamicBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) {
PhysicsServer2D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position);
}
-void RigidBody2D::apply_torque_impulse(real_t p_torque) {
+void RigidDynamicBody2D::apply_torque_impulse(real_t p_torque) {
PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque);
}
-void RigidBody2D::set_applied_force(const Vector2 &p_force) {
+void RigidDynamicBody2D::set_applied_force(const Vector2 &p_force) {
PhysicsServer2D::get_singleton()->body_set_applied_force(get_rid(), p_force);
};
-Vector2 RigidBody2D::get_applied_force() const {
+Vector2 RigidDynamicBody2D::get_applied_force() const {
return PhysicsServer2D::get_singleton()->body_get_applied_force(get_rid());
};
-void RigidBody2D::set_applied_torque(const real_t p_torque) {
+void RigidDynamicBody2D::set_applied_torque(const real_t p_torque) {
PhysicsServer2D::get_singleton()->body_set_applied_torque(get_rid(), p_torque);
};
-real_t RigidBody2D::get_applied_torque() const {
+real_t RigidDynamicBody2D::get_applied_torque() const {
return PhysicsServer2D::get_singleton()->body_get_applied_torque(get_rid());
};
-void RigidBody2D::add_central_force(const Vector2 &p_force) {
+void RigidDynamicBody2D::add_central_force(const Vector2 &p_force) {
PhysicsServer2D::get_singleton()->body_add_central_force(get_rid(), p_force);
}
-void RigidBody2D::add_force(const Vector2 &p_force, const Vector2 &p_position) {
+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 RigidBody2D::add_torque(const real_t p_torque) {
+void RigidDynamicBody2D::add_torque(const real_t p_torque) {
PhysicsServer2D::get_singleton()->body_add_torque(get_rid(), p_torque);
}
-void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) {
+void RigidDynamicBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) {
ccd_mode = p_mode;
PhysicsServer2D::get_singleton()->body_set_continuous_collision_detection_mode(get_rid(), PhysicsServer2D::CCDMode(p_mode));
}
-RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() const {
+RigidDynamicBody2D::CCDMode RigidDynamicBody2D::get_continuous_collision_detection_mode() const {
return ccd_mode;
}
-TypedArray<Node2D> RigidBody2D::get_colliding_bodies() const {
+TypedArray<Node2D> RigidDynamicBody2D::get_colliding_bodies() const {
ERR_FAIL_COND_V(!contact_monitor, Array());
TypedArray<Node2D> ret;
@@ -789,7 +827,7 @@ TypedArray<Node2D> RigidBody2D::get_colliding_bodies() const {
return ret;
}
-void RigidBody2D::set_contact_monitor(bool p_enabled) {
+void RigidDynamicBody2D::set_contact_monitor(bool p_enabled) {
if (p_enabled == is_contact_monitor_enabled()) {
return;
}
@@ -803,8 +841,8 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
Node *node = Object::cast_to<Node>(obj);
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree));
+ 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));
}
}
@@ -816,11 +854,11 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
}
}
-bool RigidBody2D::is_contact_monitor_enabled() const {
+bool RigidDynamicBody2D::is_contact_monitor_enabled() const {
return contact_monitor != nullptr;
}
-void RigidBody2D::_notification(int p_what) {
+void RigidDynamicBody2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -838,90 +876,95 @@ void RigidBody2D::_notification(int p_what) {
#endif
}
-TypedArray<String> RigidBody2D::get_configuration_warnings() const {
+TypedArray<String> RigidDynamicBody2D::get_configuration_warnings() const {
Transform2D t = get_transform();
TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
- if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (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 RigidBody2D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ 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."));
}
return warnings;
}
-void RigidBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidBody2D::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &RigidBody2D::get_mode);
+void RigidDynamicBody2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody2D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody2D::get_mass);
+
+ ClassDB::bind_method(D_METHOD("get_inertia"), &RigidDynamicBody2D::get_inertia);
+ ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidDynamicBody2D::set_inertia);
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody2D::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody2D::get_mass);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidDynamicBody2D::set_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidDynamicBody2D::get_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody2D::get_inertia);
- ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody2D::set_inertia);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidDynamicBody2D::set_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidDynamicBody2D::get_center_of_mass);
- ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody2D::set_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody2D::get_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidDynamicBody2D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidDynamicBody2D::get_physics_material_override);
- ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody2D::set_center_of_mass);
- ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody2D::get_center_of_mass);
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidDynamicBody2D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidDynamicBody2D::get_gravity_scale);
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override);
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidDynamicBody2D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidDynamicBody2D::get_linear_damp);
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale);
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidDynamicBody2D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidDynamicBody2D::get_angular_damp);
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody2D::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody2D::get_linear_damp);
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidDynamicBody2D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidDynamicBody2D::get_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody2D::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody2D::get_angular_damp);
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidDynamicBody2D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidDynamicBody2D::get_angular_velocity);
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody2D::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody2D::get_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody2D::set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody2D::get_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody2D::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody2D::get_angular_velocity);
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody2D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody2D::is_using_custom_integrator);
- ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody2D::set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody2D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidDynamicBody2D::set_contact_monitor);
+ ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidDynamicBody2D::is_contact_monitor_enabled);
- ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody2D::set_use_custom_integrator);
- ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody2D::is_using_custom_integrator);
+ ClassDB::bind_method(D_METHOD("set_continuous_collision_detection_mode", "mode"), &RigidDynamicBody2D::set_continuous_collision_detection_mode);
+ ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidDynamicBody2D::get_continuous_collision_detection_mode);
- ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody2D::set_contact_monitor);
- ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody2D::is_contact_monitor_enabled);
+ ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidDynamicBody2D::set_axis_velocity);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidDynamicBody2D::apply_central_impulse, Vector2());
+ 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_continuous_collision_detection_mode", "mode"), &RigidBody2D::set_continuous_collision_detection_mode);
- ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidBody2D::get_continuous_collision_detection_mode);
+ 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("set_axis_velocity", "axis_velocity"), &RigidBody2D::set_axis_velocity);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody2D::apply_central_impulse, Vector2());
- ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody2D::apply_impulse, Vector2());
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidBody2D::apply_torque_impulse);
+ 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("set_applied_force", "force"), &RigidBody2D::set_applied_force);
- ClassDB::bind_method(D_METHOD("get_applied_force"), &RigidBody2D::get_applied_force);
+ 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_applied_torque", "torque"), &RigidBody2D::set_applied_torque);
- ClassDB::bind_method(D_METHOD("get_applied_torque"), &RigidBody2D::get_applied_torque);
+ ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidDynamicBody2D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody2D::is_sleeping);
- ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody2D::add_central_force);
- ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody2D::add_force, Vector2());
- ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody2D::add_torque);
+ ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody2D::set_can_sleep);
+ ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody2D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody2D::set_sleeping);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody2D::is_sleeping);
+ ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody2D::set_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody2D::is_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep);
- ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep);
+ ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody2D::set_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody2D::is_freeze_enabled);
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
+ ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody2D::set_freeze_mode);
+ ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody2D::get_freeze_mode);
+
+ ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody2D::get_colliding_bodies);
GDVIRTUAL_BIND(_integrate_forces, "state");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
@@ -935,6 +978,9 @@ void RigidBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode");
ADD_GROUP("Linear", "linear_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
@@ -951,10 +997,8 @@ void RigidBody2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("sleeping_state_changed"));
- BIND_ENUM_CONSTANT(MODE_DYNAMIC);
- BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
- BIND_ENUM_CONSTANT(MODE_KINEMATIC);
+ BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC);
+ BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC);
BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO);
BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM);
@@ -964,7 +1008,7 @@ void RigidBody2D::_bind_methods() {
BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
}
-void RigidBody2D::_validate_property(PropertyInfo &property) const {
+void RigidDynamicBody2D::_validate_property(PropertyInfo &property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
if (property.name == "center_of_mass") {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
@@ -972,18 +1016,18 @@ void RigidBody2D::_validate_property(PropertyInfo &property) const {
}
}
-RigidBody2D::RigidBody2D() :
+RigidDynamicBody2D::RigidDynamicBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) {
PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-RigidBody2D::~RigidBody2D() {
+RigidDynamicBody2D::~RigidDynamicBody2D() {
if (contact_monitor) {
memdelete(contact_monitor);
}
}
-void RigidBody2D::_reload_physics_characteristics() {
+void RigidDynamicBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1);
@@ -1089,9 +1133,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
Transform2D gt = get_global_transform();
- if (result.travel.length() > margin) {
- gt.elements[2] -= result.travel.slide(up_direction);
- } else {
+ if (result.travel.length() <= margin + CMP_EPSILON) {
gt.elements[2] -= result.travel;
}
set_global_transform(gt);
@@ -1110,7 +1152,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Avoid to move forward on a wall if floor_block_on_wall is true.
if (p_was_on_floor && !on_floor && !vel_dir_facing_up) {
// If the movement is large the body can be prevented from reaching the walls.
- if (result.travel.length() <= margin) {
+ if (result.travel.length() <= margin + CMP_EPSILON) {
// Cancels the motion.
Transform2D gt = get_global_transform();
gt.elements[2] -= result.travel;
@@ -1239,13 +1281,16 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) {
}
void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) {
- if (Math::is_equal_approx(floor_snap_length, 0) || on_floor || !was_on_floor || vel_dir_facing_up) {
+ if (on_floor || !was_on_floor || vel_dir_facing_up) {
return;
}
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
+
Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
- if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
+ if (move_and_collide(-up_direction * length, result, margin, true, false, true)) {
bool apply = true;
if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true;
@@ -1273,12 +1318,15 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
}
bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) {
- if (Math::is_equal_approx(floor_snap_length, 0) || up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) {
+ if (up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) {
return false;
}
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
+
PhysicsServer2D::MotionResult result;
- if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
+ if (move_and_collide(-up_direction * length, result, margin, true, false, true)) {
if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
return true;
}
@@ -1306,11 +1354,7 @@ void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResu
void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) {
platform_rid = p_result.collider;
platform_velocity = p_result.collider_velocity;
- platform_layer = 0;
- CollisionObject2D *collision_object = Object::cast_to<CollisionObject2D>(ObjectDB::get_instance(p_result.collider_id));
- if (collision_object) {
- platform_layer = collision_object->get_collision_layer();
- }
+ platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid);
}
const Vector2 &CharacterBody2D::get_linear_velocity() const {
@@ -1373,7 +1417,8 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) {
slide_colliders.resize(p_bounce + 1);
}
- if (slide_colliders[p_bounce].is_null()) {
+ // Create a new instance when the cached reference is invalid or still in use in script.
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
@@ -1570,7 +1615,7 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1000,0.1"), "set_floor_snap_length", "get_floor_snap_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_floor_snap_length", "get_floor_snap_length");
ADD_GROUP("Moving platform", "moving_platform");
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");
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 1d6437a3ad..e789ac4cb7 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -92,7 +92,7 @@ class AnimatableBody2D : public StaticBody2D {
GDCLASS(AnimatableBody2D, StaticBody2D);
private:
- bool sync_to_physics = false;
+ bool sync_to_physics = true;
Transform2D last_valid_transform;
@@ -113,15 +113,13 @@ private:
bool is_sync_to_physics_enabled() const;
};
-class RigidBody2D : public PhysicsBody2D {
- GDCLASS(RigidBody2D, PhysicsBody2D);
+class RigidDynamicBody2D : public PhysicsBody2D {
+ GDCLASS(RigidDynamicBody2D, PhysicsBody2D);
public:
- enum Mode {
- MODE_DYNAMIC,
- MODE_STATIC,
- MODE_DYNAMIC_LOCKED,
- MODE_KINEMATIC,
+ enum FreezeMode {
+ FREEZE_MODE_STATIC,
+ FREEZE_MODE_KINEMATIC,
};
enum CenterOfMassMode {
@@ -137,7 +135,9 @@ public:
private:
bool can_sleep = true;
- Mode mode = MODE_DYNAMIC;
+ bool lock_rotation = false;
+ bool freeze = false;
+ FreezeMode freeze_mode = FREEZE_MODE_STATIC;
real_t mass = 1.0;
real_t inertia = 0.0;
@@ -177,7 +177,7 @@ private:
local_shape = p_ls;
}
};
- struct RigidBody2D_RemoveAction {
+ struct RigidDynamicBody2D_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
@@ -211,9 +211,17 @@ protected:
GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *)
+ void _apply_body_mode();
+
public:
- void set_mode(Mode p_mode);
- Mode get_mode() const;
+ void set_lock_rotation_enabled(bool p_lock_rotation);
+ bool is_lock_rotation_enabled() const;
+
+ void set_freeze_enabled(bool p_freeze);
+ bool is_freeze_enabled() const;
+
+ void set_freeze_mode(FreezeMode p_freeze_mode);
+ FreezeMode get_freeze_mode() const;
void set_mass(real_t p_mass);
real_t get_mass() const;
@@ -283,16 +291,16 @@ public:
virtual TypedArray<String> get_configuration_warnings() const override;
- RigidBody2D();
- ~RigidBody2D();
+ RigidDynamicBody2D();
+ ~RigidDynamicBody2D();
private:
void _reload_physics_characteristics();
};
-VARIANT_ENUM_CAST(RigidBody2D::Mode);
-VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode);
-VARIANT_ENUM_CAST(RigidBody2D::CCDMode);
+VARIANT_ENUM_CAST(RigidDynamicBody2D::FreezeMode);
+VARIANT_ENUM_CAST(RigidDynamicBody2D::CenterOfMassMode);
+VARIANT_ENUM_CAST(RigidDynamicBody2D::CCDMode);
class CharacterBody2D : public PhysicsBody2D {
GDCLASS(CharacterBody2D, PhysicsBody2D);
@@ -327,14 +335,14 @@ private:
real_t margin = 0.08;
MotionMode motion_mode = MOTION_MODE_GROUNDED;
- bool floor_stop_on_slope = false;
bool floor_constant_speed = false;
+ bool floor_stop_on_slope = true;
bool floor_block_on_wall = true;
bool slide_on_ceiling = true;
int max_slides = 4;
int platform_layer;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
- float floor_snap_length = 0;
+ real_t floor_snap_length = 1;
real_t free_mode_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;
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 4bbbc3575d..63a0fb9b89 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -456,7 +456,7 @@ void Bone2D::calculate_length_and_rotation() {
if (child) {
Vector2 child_local_pos = to_local(child->get_global_position());
length = child_local_pos.length();
- bone_angle = Math::atan2(child_local_pos.normalized().y, child_local_pos.normalized().x);
+ bone_angle = child_local_pos.normalized().angle();
calculated = true;
break;
}
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index e899b9a8ef..929233e4e0 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -261,6 +261,7 @@ void TileMap::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
pending_update = true;
+ _clear_internals();
_recreate_internals();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -298,6 +299,7 @@ void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
if (tile_set.is_valid()) {
tile_set->connect("changed", callable_mp(this, &TileMap::_tile_set_changed));
+ _clear_internals();
_recreate_internals();
}
@@ -308,6 +310,7 @@ void TileMap::set_quadrant_size(int p_size) {
ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
quadrant_size = p_size;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
}
@@ -327,6 +330,9 @@ void TileMap::add_layer(int p_to_pos) {
ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
+ // Must clear before adding the layer.
+ _clear_internals();
+
layers.insert(p_to_pos, TileMapLayer());
_recreate_internals();
notify_property_list_changed();
@@ -340,6 +346,9 @@ void TileMap::move_layer(int p_layer, int p_to_pos) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
+ // Clear before shuffling layers.
+ _clear_internals();
+
TileMapLayer tl = layers[p_layer];
layers.insert(p_to_pos, tl);
layers.remove(p_to_pos < p_layer ? p_layer + 1 : p_layer);
@@ -358,6 +367,9 @@ void TileMap::move_layer(int p_layer, int p_to_pos) {
void TileMap::remove_layer(int p_layer) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
+ // Clear before removing the layer.
+ _clear_internals();
+
layers.remove(p_layer);
_recreate_internals();
notify_property_list_changed();
@@ -385,6 +397,7 @@ String TileMap::get_layer_name(int p_layer) const {
void TileMap::set_layer_enabled(int p_layer, bool p_enabled) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].enabled = p_enabled;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
@@ -399,6 +412,7 @@ bool TileMap::is_layer_enabled(int p_layer) const {
void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].y_sort_enabled = p_y_sort_enabled;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
@@ -413,6 +427,7 @@ bool TileMap::is_layer_y_sort_enabled(int p_layer) const {
void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].y_sort_origin = p_y_sort_origin;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
}
@@ -425,6 +440,7 @@ int TileMap::get_layer_y_sort_origin(int p_layer) const {
void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].z_index = p_z_index;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
@@ -438,6 +454,7 @@ int TileMap::get_layer_z_index(int p_layer) const {
void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_collision) {
collision_visibility_mode = p_show_collision;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
}
@@ -448,6 +465,7 @@ TileMap::VisibilityMode TileMap::get_collision_visibility_mode() {
void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navigation) {
navigation_visibility_mode = p_show_navigation;
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
}
@@ -458,6 +476,7 @@ TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() {
void TileMap::set_y_sort_enabled(bool p_enable) {
Node2D::set_y_sort_enabled(p_enable);
+ _clear_internals();
_recreate_internals();
emit_signal(SNAME("changed"));
}
@@ -578,10 +597,10 @@ void TileMap::_update_dirty_quadrants() {
}
void TileMap::_recreate_internals() {
- // Clear all internals.
- _clear_internals();
-
for (unsigned int layer = 0; layer < layers.size(); layer++) {
+ // Make sure that _clear_internals() was called prior.
+ ERR_FAIL_COND_MSG(layers[layer].quadrant_map.size() > 0, "TileMap layer " + itos(layer) + " had a non-empty quadrant map.");
+
if (!layers[layer].enabled) {
continue;
}
@@ -872,7 +891,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
modulate.a *= 0.3;
}
}
- draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, modulate);
+ draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -989,15 +1008,19 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
}
-void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) {
+void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
-
TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
+ // Check for the frame.
+ if (p_frame >= 0) {
+ ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
+ }
+
// Get the texture.
Ref<Texture2D> tex = atlas_source->get_texture();
if (!tex.is_valid()) {
@@ -1013,13 +1036,15 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe
// Get tile data.
TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
- // Compute the offset
- Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords);
+ // Get the tile modulation.
+ Color modulate = tile_data->get_modulate() * p_modulation;
+
+ // Compute the offset.
Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(p_atlas_coords, p_alternative_tile);
- // Compute the destination rectangle in the CanvasItem.
+ // Get destination rect.
Rect2 dest_rect;
- dest_rect.size = source_rect.size;
+ dest_rect.size = atlas_source->get_tile_texture_region(p_atlas_coords).size;
dest_rect.size.x += FP_ADJUST;
dest_rect.size.y += FP_ADJUST;
@@ -1038,12 +1063,28 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe
dest_rect.size.y = -dest_rect.size.y;
}
- // Get the tile modulation.
- Color modulate = tile_data->get_modulate();
- modulate = Color(modulate.r * p_modulation.r, modulate.g * p_modulation.g, modulate.b * p_modulation.b, modulate.a * p_modulation.a);
-
// Draw the tile.
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ if (p_frame >= 0) {
+ Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, p_frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
+ Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, 0);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else {
+ real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
+ real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
+ real_t time = 0.0;
+ for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
+ real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed;
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, 0.0);
+
+ Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+
+ time += frame_duration;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
+ }
}
}
@@ -1993,10 +2034,22 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
return false;
} else if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
int index = components[0].trim_prefix("layer_").to_int();
- if (index < 0 || index >= (int)layers.size()) {
+ if (index < 0) {
return false;
}
+ if (index >= (int)layers.size()) {
+ _clear_internals();
+ while (index >= (int)layers.size()) {
+ layers.push_back(TileMapLayer());
+ }
+ _recreate_internals();
+
+ notify_property_list_changed();
+ emit_signal(SNAME("changed"));
+ update_configuration_warnings();
+ }
+
if (components[1] == "name") {
set_layer_name(index, p_value);
return true;
@@ -3000,6 +3053,7 @@ void TileMap::_bind_methods() {
void TileMap::_tile_set_changed() {
emit_signal(SNAME("changed"));
+ _clear_internals();
_recreate_internals();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 3ac50fc7cc..ca38baa550 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -305,7 +305,7 @@ public:
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
- static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
+ static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
// Layers management.
int get_layers_count() const;
diff --git a/scene/3d/listener_3d.cpp b/scene/3d/audio_listener_3d.cpp
index 1c52933ee5..b2319e40d7 100644
--- a/scene/3d/listener_3d.cpp
+++ b/scene/3d/audio_listener_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* listener_3d.cpp */
+/* audio_listener_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,18 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "listener_3d.h"
+#include "audio_listener_3d.h"
#include "scene/main/viewport.h"
-void Listener3D::_update_audio_listener_state() {
+void AudioListener3D::_update_audio_listener_state() {
}
-void Listener3D::_request_listener_update() {
+void AudioListener3D::_request_listener_update() {
_update_listener();
}
-bool Listener3D::_set(const StringName &p_name, const Variant &p_value) {
+bool AudioListener3D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "current") {
if (p_value.operator bool()) {
make_current();
@@ -53,7 +53,7 @@ bool Listener3D::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
-bool Listener3D::_get(const StringName &p_name, Variant &r_ret) const {
+bool AudioListener3D::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "current") {
if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
r_ret = current;
@@ -67,20 +67,20 @@ bool Listener3D::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-void Listener3D::_get_property_list(List<PropertyInfo> *p_list) const {
+void AudioListener3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
}
-void Listener3D::_update_listener() {
+void AudioListener3D::_update_listener() {
if (is_inside_tree() && is_current()) {
get_viewport()->_listener_transform_3d_changed_notify();
}
}
-void Listener3D::_notification(int p_what) {
+void AudioListener3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
- bool first_listener = get_viewport()->_listener_3d_add(this);
+ bool first_listener = get_viewport()->_audio_listener_3d_add(this);
if (!get_tree()->is_node_being_edited(this) && (current || first_listener)) {
make_current();
}
@@ -99,41 +99,41 @@ void Listener3D::_notification(int p_what) {
}
}
- get_viewport()->_listener_3d_remove(this);
+ get_viewport()->_audio_listener_3d_remove(this);
} break;
}
}
-Transform3D Listener3D::get_listener_transform() const {
+Transform3D AudioListener3D::get_listener_transform() const {
return get_global_transform().orthonormalized();
}
-void Listener3D::make_current() {
+void AudioListener3D::make_current() {
current = true;
if (!is_inside_tree()) {
return;
}
- get_viewport()->_listener_3d_set(this);
+ get_viewport()->_audio_listener_3d_set(this);
}
-void Listener3D::clear_current() {
+void AudioListener3D::clear_current() {
current = false;
if (!is_inside_tree()) {
return;
}
- if (get_viewport()->get_listener_3d() == this) {
- get_viewport()->_listener_3d_set(nullptr);
- get_viewport()->_listener_3d_make_next_current(this);
+ if (get_viewport()->get_audio_listener_3d() == this) {
+ get_viewport()->_audio_listener_3d_set(nullptr);
+ get_viewport()->_audio_listener_3d_make_next_current(this);
}
}
-bool Listener3D::is_current() const {
+bool AudioListener3D::is_current() const {
if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
- return get_viewport()->get_listener_3d() == this;
+ return get_viewport()->get_audio_listener_3d() == this;
} else {
return current;
}
@@ -141,27 +141,16 @@ bool Listener3D::is_current() const {
return false;
}
-bool Listener3D::_can_gizmo_scale() const {
- return false;
-}
-
-RES Listener3D::_get_gizmo_geometry() const {
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
-
- return mesh;
-}
-
-void Listener3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("make_current"), &Listener3D::make_current);
- ClassDB::bind_method(D_METHOD("clear_current"), &Listener3D::clear_current);
- ClassDB::bind_method(D_METHOD("is_current"), &Listener3D::is_current);
- ClassDB::bind_method(D_METHOD("get_listener_transform"), &Listener3D::get_listener_transform);
+void AudioListener3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("make_current"), &AudioListener3D::make_current);
+ ClassDB::bind_method(D_METHOD("clear_current"), &AudioListener3D::clear_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &AudioListener3D::is_current);
+ ClassDB::bind_method(D_METHOD("get_listener_transform"), &AudioListener3D::get_listener_transform);
}
-Listener3D::Listener3D() {
+AudioListener3D::AudioListener3D() {
set_notify_transform(true);
- //active=false;
}
-Listener3D::~Listener3D() {
+AudioListener3D::~AudioListener3D() {
}
diff --git a/scene/3d/listener_3d.h b/scene/3d/audio_listener_3d.h
index 25eacf5135..492cacb0e9 100644
--- a/scene/3d/listener_3d.h
+++ b/scene/3d/audio_listener_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* listener_3d.h */
+/* audio_listener_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -33,8 +33,8 @@
#include "scene/3d/node_3d.h"
-class Listener3D : public Node3D {
- GDCLASS(Listener3D, Node3D);
+class AudioListener3D : public Node3D {
+ GDCLASS(AudioListener3D, Node3D);
private:
bool force_change = false;
@@ -42,9 +42,6 @@ private:
RID scenario_id;
- virtual bool _can_gizmo_scale() const;
- virtual RES _get_gizmo_geometry() const;
-
friend class Viewport;
void _update_audio_listener_state();
@@ -69,8 +66,8 @@ public:
void set_visible_layers(uint32_t p_layers);
uint32_t get_visible_layers() const;
- Listener3D();
- ~Listener3D();
+ AudioListener3D();
+ ~AudioListener3D();
};
#endif
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 907c6cd03a..a54b10ba70 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -31,8 +31,8 @@
#include "audio_stream_player_3d.h"
#include "scene/3d/area_3d.h"
+#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/camera_3d.h"
-#include "scene/3d/listener_3d.h"
#include "scene/main/viewport.h"
// Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004)
@@ -391,7 +391,7 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
bool listener_is_camera = true;
Node3D *listener_node = camera;
- Listener3D *listener = vp->get_listener_3d();
+ AudioListener3D *listener = vp->get_audio_listener_3d();
if (listener) {
listener_node = listener;
listener_is_camera = false;
@@ -713,15 +713,6 @@ AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model
return attenuation_model;
}
-void AudioStreamPlayer3D::set_out_of_range_mode(OutOfRangeMode p_mode) {
- ERR_FAIL_INDEX((int)p_mode, 2);
- out_of_range_mode = p_mode;
-}
-
-AudioStreamPlayer3D::OutOfRangeMode AudioStreamPlayer3D::get_out_of_range_mode() const {
- return out_of_range_mode;
-}
-
void AudioStreamPlayer3D::set_doppler_tracking(DopplerTracking p_tracking) {
if (doppler_tracking == p_tracking) {
return;
@@ -832,9 +823,6 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_attenuation_model", "model"), &AudioStreamPlayer3D::set_attenuation_model);
ClassDB::bind_method(D_METHOD("get_attenuation_model"), &AudioStreamPlayer3D::get_attenuation_model);
- ClassDB::bind_method(D_METHOD("set_out_of_range_mode", "mode"), &AudioStreamPlayer3D::set_out_of_range_mode);
- ClassDB::bind_method(D_METHOD("get_out_of_range_mode"), &AudioStreamPlayer3D::get_out_of_range_mode);
-
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &AudioStreamPlayer3D::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &AudioStreamPlayer3D::get_doppler_tracking);
@@ -856,7 +844,6 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
@@ -875,9 +862,6 @@ void AudioStreamPlayer3D::_bind_methods() {
BIND_ENUM_CONSTANT(ATTENUATION_LOGARITHMIC);
BIND_ENUM_CONSTANT(ATTENUATION_DISABLED);
- BIND_ENUM_CONSTANT(OUT_OF_RANGE_MIX);
- BIND_ENUM_CONSTANT(OUT_OF_RANGE_PAUSE);
-
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED);
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP);
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index abd5a841b2..697bbe2381 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -51,11 +51,6 @@ public:
ATTENUATION_DISABLED,
};
- enum OutOfRangeMode {
- OUT_OF_RANGE_MIX,
- OUT_OF_RANGE_PAUSE,
- };
-
enum DopplerTracking {
DOPPLER_TRACKING_DISABLED,
DOPPLER_TRACKING_IDLE_STEP,
@@ -118,8 +113,6 @@ private:
DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED;
- OutOfRangeMode out_of_range_mode = OUT_OF_RANGE_MIX;
-
float _get_attenuation_db(float p_distance) const;
protected:
@@ -182,9 +175,6 @@ public:
void set_attenuation_model(AttenuationModel p_model);
AttenuationModel get_attenuation_model() const;
- void set_out_of_range_mode(OutOfRangeMode p_mode);
- OutOfRangeMode get_out_of_range_mode() const;
-
void set_doppler_tracking(DopplerTracking p_tracking);
DopplerTracking get_doppler_tracking() const;
@@ -198,6 +188,5 @@ public:
};
VARIANT_ENUM_CAST(AudioStreamPlayer3D::AttenuationModel)
-VARIANT_ENUM_CAST(AudioStreamPlayer3D::OutOfRangeMode)
VARIANT_ENUM_CAST(AudioStreamPlayer3D::DopplerTracking)
#endif // AUDIO_STREAM_PLAYER_3D_H
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index 70361f4787..afd11482e3 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -110,7 +110,7 @@ TypedArray<String> BoneAttachment3D::get_configuration_warnings() const {
} else {
Skeleton3D *parent = Object::cast_to<Skeleton3D>(get_parent());
if (!parent) {
- warnings.append(TTR("Parent node is not a Skeleton3D node! Please use an extenral Skeleton3D if you intend to use the BoneAttachment3D without it being a child of a Skeleton3D node."));
+ warnings.append(TTR("Parent node is not a Skeleton3D node! Please use an external Skeleton3D if you intend to use the BoneAttachment3D without it being a child of a Skeleton3D node."));
}
}
@@ -161,7 +161,7 @@ void BoneAttachment3D::_check_bind() {
bone_idx = sk->find_bone(bone_name);
}
if (bone_idx != -1) {
- sk->call_deferred("connect", "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
+ sk->call_deferred(SNAME("connect"), "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
bound = true;
call_deferred(SNAME("on_bone_pose_update"), bone_idx);
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 3ada9072c2..9aad338d15 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -254,10 +254,6 @@ bool Camera3D::is_current() const {
}
}
-bool Camera3D::_can_gizmo_scale() const {
- return false;
-}
-
Vector3 Camera3D::project_ray_normal(const Point2 &p_pos) const {
Vector3 ray = project_local_ray_normal(p_pos);
return get_camera_transform().basis.xform(ray).normalized();
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index 3b704944b0..c1af7fa4f7 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -79,8 +79,6 @@ private:
Ref<Environment> environment;
Ref<CameraEffects> effects;
- virtual bool _can_gizmo_scale() const;
-
// void _camera_make_current(Node *p_camera);
friend class Viewport;
void _update_audio_listener_state();
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index d5835586f9..6328d9c67d 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -170,7 +170,7 @@ TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(TTR("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(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidDynamicBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index d4668a24f2..4e496fba47 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -115,7 +115,7 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(TTR("CollisionShape3D 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(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidDynamicBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
@@ -123,10 +123,9 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
}
if (shape.is_valid() &&
- Object::cast_to<RigidBody3D>(get_parent()) &&
- Object::cast_to<ConcavePolygonShape3D>(*shape) &&
- Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
- warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
+ Object::cast_to<RigidDynamicBody3D>(get_parent()) &&
+ Object::cast_to<ConcavePolygonShape3D>(*shape)) {
+ warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidDynamicBody3D in another mode than static."));
}
return warnings;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index baf28ae102..32a62d8c7e 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -469,7 +469,7 @@ void GPUParticles3D::_skinning_changed() {
if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
xforms.resize(draw_pass->get_builtin_bind_pose_count());
for (int j = 0; j < draw_pass->get_builtin_bind_pose_count(); j++) {
- xforms.write[i] = draw_pass->get_builtin_bind_pose(j);
+ xforms.write[j] = draw_pass->get_builtin_bind_pose(j);
}
break;
}
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index a34a30913e..4fa34615bf 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -420,7 +420,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+ if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
continue;
}
@@ -438,7 +438,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+ if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
continue;
}
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index ab417fafdd..c787ba5087 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -30,10 +30,6 @@
#include "light_3d.h"
-bool Light3D::_can_gizmo_scale() const {
- return false;
-}
-
void Light3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
param[p_param] = p_value;
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index ecea60339f..f788c323f7 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -86,8 +86,6 @@ private:
protected:
RID light;
- virtual bool _can_gizmo_scale() const;
-
static void _bind_methods();
void _notification(int p_what);
virtual void _validate_property(PropertyInfo &property) const override;
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 7dd083e314..b56f0fd145 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -467,7 +467,7 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc
}
}
if (i == 0) {
- centers.push_back(bounds.position + bounds.size * 0.5);
+ centers.push_back(bounds.get_center());
} else {
bounds_all.merge_with(bounds);
}
@@ -555,7 +555,7 @@ void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cel
subcell.position = Vector3(pos) * p_cell_size;
subcell.size = Vector3(half_size, half_size, half_size) * p_cell_size;
- if (!Geometry3D::triangle_box_overlap(subcell.position + subcell.size * 0.5, subcell.size * 0.5, p_triangle)) {
+ if (!Geometry3D::triangle_box_overlap(subcell.get_center(), subcell.size * 0.5, p_triangle)) {
continue;
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 00c6664e65..bbf2c81a92 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -38,8 +38,8 @@
#endif
void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1));
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
@@ -95,10 +95,14 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, int p_max_collisions) {
PhysicsServer3D::MotionResult result;
- if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
- if (motion_cache.is_null()) {
+ // 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();
+
+ if (move_and_collide(p_motion * delta, result, p_margin, p_test_only, p_max_collisions)) {
+ // 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();
motion_cache->owner = this;
}
@@ -111,9 +115,9 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_t
return Ref<KinematicCollision3D>();
}
-bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
+bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only, int p_max_collisions, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
Transform3D gt = get_global_transform();
- bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_collide_separation_ray, p_exclude);
+ bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_max_collisions, p_collide_separation_ray, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@@ -125,9 +129,9 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::M
if (colliding) {
// Can't just use margin as a threshold because collision depth is calculated on unsafe motion,
// so even in normal resting cases the depth can be a bit more than the margin.
- precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction);
+ precision += motion_length * (r_result.unsafe_fraction - r_result.safe_fraction);
- if (r_result.collision_depth > (real_t)p_margin + precision) {
+ if (r_result.collisions[0].depth > (real_t)p_margin + precision) {
p_cancel_sliding = false;
}
}
@@ -167,7 +171,7 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::M
return colliding;
}
-bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) {
+bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer3D::MotionResult *r = nullptr;
@@ -176,7 +180,10 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion
r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
+ // 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();
+
+ return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r, p_max_collisions);
}
void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
@@ -364,7 +371,7 @@ AnimatableBody3D::AnimatableBody3D() :
_update_kinematic_motion();
}
-void RigidBody3D::_body_enter_tree(ObjectID p_id) {
+void RigidDynamicBody3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -387,7 +394,7 @@ void RigidBody3D::_body_enter_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidBody3D::_body_exit_tree(ObjectID p_id) {
+void RigidDynamicBody3D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -408,7 +415,7 @@ void RigidBody3D::_body_exit_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -427,8 +434,8 @@ void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
//E->get().rc=0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree), make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -454,8 +461,8 @@ void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
if (E->get().shapes.is_empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree));
if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
@@ -469,19 +476,19 @@ void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
}
}
-struct _RigidBodyInOut {
+struct _RigidDynamicBodyInOut {
RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
};
-void RigidBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- RigidBody3D *body = (RigidBody3D *)p_instance;
+void RigidDynamicBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ RigidDynamicBody3D *body = (RigidDynamicBody3D *)p_instance;
body->_body_state_changed(p_state);
}
-void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
set_ignore_transform_notification(true);
set_global_transform(p_state->get_transform());
@@ -512,9 +519,9 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
}
}
- _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBodyInOut));
+ _RigidDynamicBodyInOut *toadd = (_RigidDynamicBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidDynamicBodyInOut));
int toadd_count = 0; //state->get_contact_count();
- RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction));
+ RigidDynamicBody3D_RemoveAction *toremove = (RigidDynamicBody3D_RemoveAction *)alloca(rc * sizeof(RigidDynamicBody3D_RemoveAction));
int toremove_count = 0;
//put the ones to add
@@ -580,7 +587,7 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
}
}
-void RigidBody3D::_notification(int p_what) {
+void RigidDynamicBody3D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -598,40 +605,73 @@ void RigidBody3D::_notification(int p_what) {
#endif
}
-void RigidBody3D::set_mode(Mode p_mode) {
- mode = p_mode;
- switch (p_mode) {
- case MODE_DYNAMIC: {
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
- } break;
- case MODE_STATIC: {
- set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
- } break;
- case MODE_DYNAMIC_LOCKED: {
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED);
- } break;
- case MODE_KINEMATIC: {
- set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
- } break;
+void RigidDynamicBody3D::_apply_body_mode() {
+ if (freeze) {
+ switch (freeze_mode) {
+ case FREEZE_MODE_STATIC: {
+ set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
+ } break;
+ case FREEZE_MODE_KINEMATIC: {
+ set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
+ } break;
+ }
+ } else if (lock_rotation) {
+ set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR);
+ } else {
+ set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
+ }
+}
+
+void RigidDynamicBody3D::set_lock_rotation_enabled(bool p_lock_rotation) {
+ if (p_lock_rotation == lock_rotation) {
+ return;
+ }
+
+ lock_rotation = p_lock_rotation;
+ _apply_body_mode();
+}
+
+bool RigidDynamicBody3D::is_lock_rotation_enabled() const {
+ return lock_rotation;
+}
+
+void RigidDynamicBody3D::set_freeze_enabled(bool p_freeze) {
+ if (p_freeze == freeze) {
+ return;
}
- update_configuration_warnings();
+
+ freeze = p_freeze;
+ _apply_body_mode();
}
-RigidBody3D::Mode RigidBody3D::get_mode() const {
- return mode;
+bool RigidDynamicBody3D::is_freeze_enabled() const {
+ return freeze;
}
-void RigidBody3D::set_mass(real_t p_mass) {
+void RigidDynamicBody3D::set_freeze_mode(FreezeMode p_freeze_mode) {
+ if (p_freeze_mode == freeze_mode) {
+ return;
+ }
+
+ freeze_mode = p_freeze_mode;
+ _apply_body_mode();
+}
+
+RigidDynamicBody3D::FreezeMode RigidDynamicBody3D::get_freeze_mode() const {
+ return freeze_mode;
+}
+
+void RigidDynamicBody3D::set_mass(real_t p_mass) {
ERR_FAIL_COND(p_mass <= 0);
mass = p_mass;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass);
}
-real_t RigidBody3D::get_mass() const {
+real_t RigidDynamicBody3D::get_mass() const {
return mass;
}
-void RigidBody3D::set_inertia(const Vector3 &p_inertia) {
+void RigidDynamicBody3D::set_inertia(const Vector3 &p_inertia) {
ERR_FAIL_COND(p_inertia.x < 0);
ERR_FAIL_COND(p_inertia.y < 0);
ERR_FAIL_COND(p_inertia.z < 0);
@@ -640,11 +680,11 @@ void RigidBody3D::set_inertia(const Vector3 &p_inertia) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia);
}
-const Vector3 &RigidBody3D::get_inertia() const {
+const Vector3 &RigidDynamicBody3D::get_inertia() const {
return inertia;
}
-void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
+void RigidDynamicBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
if (center_of_mass_mode == p_mode) {
return;
}
@@ -666,11 +706,11 @@ void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
}
}
-RigidBody3D::CenterOfMassMode RigidBody3D::get_center_of_mass_mode() const {
+RigidDynamicBody3D::CenterOfMassMode RigidDynamicBody3D::get_center_of_mass_mode() const {
return center_of_mass_mode;
}
-void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
+void RigidDynamicBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
if (center_of_mass == p_center_of_mass) {
return;
}
@@ -681,88 +721,88 @@ void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
}
-const Vector3 &RigidBody3D::get_center_of_mass() const {
+const Vector3 &RigidDynamicBody3D::get_center_of_mass() const {
return center_of_mass;
}
-void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+void RigidDynamicBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics));
}
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
-Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const {
+Ref<PhysicsMaterial> RigidDynamicBody3D::get_physics_material_override() const {
return physics_material_override;
}
-void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) {
+void RigidDynamicBody3D::set_gravity_scale(real_t p_gravity_scale) {
gravity_scale = p_gravity_scale;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
}
-real_t RigidBody3D::get_gravity_scale() const {
+real_t RigidDynamicBody3D::get_gravity_scale() const {
return gravity_scale;
}
-void RigidBody3D::set_linear_damp(real_t p_linear_damp) {
+void RigidDynamicBody3D::set_linear_damp(real_t p_linear_damp) {
ERR_FAIL_COND(p_linear_damp < -1);
linear_damp = p_linear_damp;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp);
}
-real_t RigidBody3D::get_linear_damp() const {
+real_t RigidDynamicBody3D::get_linear_damp() const {
return linear_damp;
}
-void RigidBody3D::set_angular_damp(real_t p_angular_damp) {
+void RigidDynamicBody3D::set_angular_damp(real_t p_angular_damp) {
ERR_FAIL_COND(p_angular_damp < -1);
angular_damp = p_angular_damp;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
}
-real_t RigidBody3D::get_angular_damp() const {
+real_t RigidDynamicBody3D::get_angular_damp() const {
return angular_damp;
}
-void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) {
+void RigidDynamicBody3D::set_axis_velocity(const Vector3 &p_axis) {
Vector3 axis = p_axis.normalized();
linear_velocity -= axis * axis.dot(linear_velocity);
linear_velocity += p_axis;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) {
+void RigidDynamicBody3D::set_linear_velocity(const Vector3 &p_velocity) {
linear_velocity = p_velocity;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-Vector3 RigidBody3D::get_linear_velocity() const {
+Vector3 RigidDynamicBody3D::get_linear_velocity() const {
return linear_velocity;
}
-void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) {
+void RigidDynamicBody3D::set_angular_velocity(const Vector3 &p_velocity) {
angular_velocity = p_velocity;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
-Vector3 RigidBody3D::get_angular_velocity() const {
+Vector3 RigidDynamicBody3D::get_angular_velocity() const {
return angular_velocity;
}
-Basis RigidBody3D::get_inverse_inertia_tensor() const {
+Basis RigidDynamicBody3D::get_inverse_inertia_tensor() const {
return inverse_inertia_tensor;
}
-void RigidBody3D::set_use_custom_integrator(bool p_enable) {
+void RigidDynamicBody3D::set_use_custom_integrator(bool p_enable) {
if (custom_integrator == p_enable) {
return;
}
@@ -771,73 +811,73 @@ void RigidBody3D::set_use_custom_integrator(bool p_enable) {
PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
}
-bool RigidBody3D::is_using_custom_integrator() {
+bool RigidDynamicBody3D::is_using_custom_integrator() {
return custom_integrator;
}
-void RigidBody3D::set_sleeping(bool p_sleeping) {
+void RigidDynamicBody3D::set_sleeping(bool p_sleeping) {
sleeping = p_sleeping;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping);
}
-void RigidBody3D::set_can_sleep(bool p_active) {
+void RigidDynamicBody3D::set_can_sleep(bool p_active) {
can_sleep = p_active;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active);
}
-bool RigidBody3D::is_able_to_sleep() const {
+bool RigidDynamicBody3D::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidBody3D::is_sleeping() const {
+bool RigidDynamicBody3D::is_sleeping() const {
return sleeping;
}
-void RigidBody3D::set_max_contacts_reported(int p_amount) {
+void RigidDynamicBody3D::set_max_contacts_reported(int p_amount) {
max_contacts_reported = p_amount;
PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
-int RigidBody3D::get_max_contacts_reported() const {
+int RigidDynamicBody3D::get_max_contacts_reported() const {
return max_contacts_reported;
}
-void RigidBody3D::add_central_force(const Vector3 &p_force) {
+void RigidDynamicBody3D::add_central_force(const Vector3 &p_force) {
PhysicsServer3D::get_singleton()->body_add_central_force(get_rid(), p_force);
}
-void RigidBody3D::add_force(const Vector3 &p_force, const Vector3 &p_position) {
+void RigidDynamicBody3D::add_force(const Vector3 &p_force, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_add_force(get_rid(), p_force, p_position);
}
-void RigidBody3D::add_torque(const Vector3 &p_torque) {
+void RigidDynamicBody3D::add_torque(const Vector3 &p_torque) {
PhysicsServer3D::get_singleton()->body_add_torque(get_rid(), p_torque);
}
-void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+void RigidDynamicBody3D::apply_central_impulse(const Vector3 &p_impulse) {
PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
}
-void RigidBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
+void RigidDynamicBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_apply_impulse(get_rid(), p_impulse, p_position);
}
-void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
+void RigidDynamicBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
PhysicsServer3D::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse);
}
-void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) {
+void RigidDynamicBody3D::set_use_continuous_collision_detection(bool p_enable) {
ccd = p_enable;
PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable);
}
-bool RigidBody3D::is_using_continuous_collision_detection() const {
+bool RigidDynamicBody3D::is_using_continuous_collision_detection() const {
return ccd;
}
-void RigidBody3D::set_contact_monitor(bool p_enabled) {
+void RigidDynamicBody3D::set_contact_monitor(bool p_enabled) {
if (p_enabled == is_contact_monitor_enabled()) {
return;
}
@@ -851,8 +891,8 @@ void RigidBody3D::set_contact_monitor(bool p_enabled) {
Node *node = Object::cast_to<Node>(obj);
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree));
}
}
@@ -864,11 +904,11 @@ void RigidBody3D::set_contact_monitor(bool p_enabled) {
}
}
-bool RigidBody3D::is_contact_monitor_enabled() const {
+bool RigidDynamicBody3D::is_contact_monitor_enabled() const {
return contact_monitor != nullptr;
}
-Array RigidBody3D::get_colliding_bodies() const {
+Array RigidDynamicBody3D::get_colliding_bodies() const {
ERR_FAIL_COND_V(!contact_monitor, Array());
Array ret;
@@ -886,87 +926,92 @@ Array RigidBody3D::get_colliding_bodies() const {
return ret;
}
-TypedArray<String> RigidBody3D::get_configuration_warnings() const {
+TypedArray<String> RigidDynamicBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
TypedArray<String> warnings = Node::get_configuration_warnings();
- if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- warnings.push_back(TTR("Size changes to RigidBody3D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ if (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05) {
+ warnings.push_back(TTR("Size changes to RigidDynamicBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void RigidBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidBody3D::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &RigidBody3D::get_mode);
+void RigidDynamicBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody3D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody3D::get_mass);
+
+ ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidDynamicBody3D::set_inertia);
+ ClassDB::bind_method(D_METHOD("get_inertia"), &RigidDynamicBody3D::get_inertia);
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidDynamicBody3D::set_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidDynamicBody3D::get_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody3D::set_inertia);
- ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody3D::get_inertia);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidDynamicBody3D::set_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidDynamicBody3D::get_center_of_mass);
- ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody3D::set_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody3D::get_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidDynamicBody3D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidDynamicBody3D::get_physics_material_override);
- ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody3D::set_center_of_mass);
- ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody3D::get_center_of_mass);
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidDynamicBody3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidDynamicBody3D::get_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override);
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidDynamicBody3D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidDynamicBody3D::get_angular_velocity);
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody3D::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody3D::get_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidDynamicBody3D::get_inverse_inertia_tensor);
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity);
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidDynamicBody3D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidDynamicBody3D::get_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor);
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidDynamicBody3D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidDynamicBody3D::get_linear_damp);
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale);
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidDynamicBody3D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidDynamicBody3D::get_angular_damp);
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody3D::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody3D::get_linear_damp);
+ ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody3D::set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody3D::get_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody3D::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody3D::get_angular_damp);
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody3D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody3D::is_using_custom_integrator);
- ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody3D::set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody3D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidDynamicBody3D::set_contact_monitor);
+ ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidDynamicBody3D::is_contact_monitor_enabled);
- ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody3D::set_use_custom_integrator);
- ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody3D::is_using_custom_integrator);
+ ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidDynamicBody3D::set_use_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidDynamicBody3D::is_using_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody3D::set_contact_monitor);
- ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody3D::is_contact_monitor_enabled);
+ ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidDynamicBody3D::set_axis_velocity);
- ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody3D::set_use_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody3D::is_using_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidDynamicBody3D::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidDynamicBody3D::add_force, Vector3());
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidDynamicBody3D::add_torque);
- ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidDynamicBody3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidDynamicBody3D::apply_impulse, Vector3());
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidDynamicBody3D::apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody3D::add_central_force);
- ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody3D::add_force, Vector3());
- ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody3D::add_torque);
+ ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidDynamicBody3D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody3D::is_sleeping);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody3D::set_can_sleep);
+ ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody3D::is_sleeping);
+ ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody3D::set_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody3D::is_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep);
- ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep);
+ ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody3D::set_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody3D::is_freeze_enabled);
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
+ ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody3D::set_freeze_mode);
+ ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody3D::get_freeze_mode);
+
+ ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody3D::get_colliding_bodies);
GDVIRTUAL_BIND(_integrate_forces, "state");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
@@ -980,6 +1025,9 @@ void RigidBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode");
ADD_GROUP("Linear", "linear_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
@@ -993,16 +1041,14 @@ void RigidBody3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("sleeping_state_changed"));
- BIND_ENUM_CONSTANT(MODE_DYNAMIC);
- BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
- BIND_ENUM_CONSTANT(MODE_KINEMATIC);
+ BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC);
+ BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC);
BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO);
BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM);
}
-void RigidBody3D::_validate_property(PropertyInfo &property) const {
+void RigidDynamicBody3D::_validate_property(PropertyInfo &property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
if (property.name == "center_of_mass") {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
@@ -1010,18 +1056,18 @@ void RigidBody3D::_validate_property(PropertyInfo &property) const {
}
}
-RigidBody3D::RigidBody3D() :
+RigidDynamicBody3D::RigidDynamicBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) {
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-RigidBody3D::~RigidBody3D() {
+RigidDynamicBody3D::~RigidDynamicBody3D() {
if (contact_monitor) {
memdelete(contact_monitor);
}
}
-void RigidBody3D::_reload_physics_characteristics() {
+void RigidDynamicBody3D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
@@ -1037,64 +1083,115 @@ void RigidBody3D::_reload_physics_characteristics() {
#define FLOOR_ANGLE_THRESHOLD 0.01
bool CharacterBody3D::move_and_slide() {
- bool was_on_floor = on_floor;
-
// 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();
-
+ previous_position = get_global_transform().origin;
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
linear_velocity[i] = 0.0;
}
}
- Vector3 current_floor_velocity = floor_velocity;
- if ((on_floor || on_wall) && on_floor_body.is_valid()) {
- //this approach makes sure there is less delay between the actual body velocity and the one we saved
- PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(on_floor_body);
- if (bs) {
- Transform3D gt = get_global_transform();
- Vector3 local_position = gt.origin - bs->get_transform().origin;
- current_floor_velocity = bs->get_velocity_at_local_position(local_position);
+ Vector3 current_platform_velocity = platform_velocity;
+
+ if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) {
+ bool excluded = false;
+ if (collision_state.floor) {
+ excluded = (moving_platform_floor_layers & platform_layer) == 0;
+ } else if (collision_state.wall) {
+ excluded = (moving_platform_wall_layers & platform_layer) == 0;
+ }
+ if (!excluded) {
+ //this approach makes sure there is less delay between the actual body velocity and the one we saved
+ PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid);
+ if (bs) {
+ Transform3D gt = get_global_transform();
+ Vector3 local_position = gt.origin - bs->get_transform().origin;
+ current_platform_velocity = bs->get_velocity_at_local_position(local_position);
+ }
+ } else {
+ current_platform_velocity = Vector3();
}
}
motion_results.clear();
- on_floor = false;
- on_ceiling = false;
- on_wall = false;
- floor_normal = Vector3();
- floor_velocity = Vector3();
- if (!current_floor_velocity.is_equal_approx(Vector3()) && on_floor_body.is_valid()) {
+ bool was_on_floor = collision_state.floor;
+ collision_state.state = 0;
+
+ if (!current_platform_velocity.is_equal_approx(Vector3())) {
PhysicsServer3D::MotionResult floor_result;
Set<RID> exclude;
- exclude.insert(on_floor_body);
- if (move_and_collide(current_floor_velocity * delta, floor_result, margin, false, false, false, exclude)) {
+ exclude.insert(platform_rid);
+ if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, 1, false, false, exclude)) {
motion_results.push_back(floor_result);
- _set_collision_direction(floor_result);
+
+ CollisionState result_state;
+ _set_collision_direction(floor_result, result_state);
}
}
- on_floor_body = RID();
- Vector3 motion = linear_velocity * delta;
+ if (motion_mode == MOTION_MODE_GROUNDED) {
+ _move_and_slide_grounded(delta, was_on_floor);
+ } else {
+ _move_and_slide_free(delta);
+ }
+
+ // Compute real velocity.
+ real_velocity = get_position_delta() / delta;
+
+ if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) {
+ // Add last platform velocity when just left a moving platform.
+ if (!collision_state.floor && !collision_state.wall) {
+ 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);
+ }
+ linear_velocity += current_platform_velocity;
+ }
+ }
+
+ // Reset the gravity accumulation when touching the ground.
+ if (collision_state.floor && linear_velocity.dot(up_direction) <= 0) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ }
+
+ return motion_results.size() > 0;
+}
+
+void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) {
+ Vector3 motion = linear_velocity * p_delta;
+ Vector3 motion_slide_up = motion.slide(up_direction);
+ Vector3 prev_floor_normal = floor_normal;
+
+ platform_rid = RID();
+ platform_velocity = Vector3();
+ floor_normal = Vector3();
+ wall_normal = Vector3();
// No sliding on first attempt to keep floor motion stable when possible,
- // when stop on slope is enabled.
+ // When stop on slope is enabled or when there is no up direction.
bool sliding_enabled = !floor_stop_on_slope;
+ // Constant speed can be applied only the first time sliding is enabled.
+ bool can_apply_constant_speed = sliding_enabled;
+ bool first_slide = true;
+ bool vel_dir_facing_up = linear_velocity.dot(up_direction) > 0;
+ Vector3 total_travel;
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionResult result;
- bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
+ bool collided = move_and_collide(motion, result, margin, false, 4, !sliding_enabled);
+
if (collided) {
motion_results.push_back(result);
- _set_collision_direction(result);
- if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
+ CollisionState previous_state = collision_state;
+
+ CollisionState result_state;
+ _set_collision_direction(result, result_state);
+
+ if (collision_state.floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
Transform3D gt = get_global_transform();
- if (result.travel.length() > margin) {
- gt.origin -= result.travel.slide(up_direction);
- } else {
+ if (result.travel.length() <= margin + CMP_EPSILON) {
gt.origin -= result.travel;
}
set_global_transform(gt);
@@ -1105,94 +1202,358 @@ bool CharacterBody3D::move_and_slide() {
if (result.remainder.is_equal_approx(Vector3())) {
motion = Vector3();
+ last_motion = result.travel;
break;
}
- if (sliding_enabled || !on_floor) {
- Vector3 slide_motion = result.remainder.slide(result.collision_normal);
- if (slide_motion.dot(linear_velocity) > 0.0) {
- motion = slide_motion;
- } else {
- motion = Vector3();
+ // Apply regular sliding by default.
+ bool apply_default_sliding = true;
+
+ // Wall collision checks.
+ if (result_state.wall && (motion_slide_up.dot(wall_normal) <= 0)) {
+ // Move on floor only checks.
+ if (floor_block_on_wall) {
+ // Needs horizontal motion from current motion instead of motion_slide_up
+ // to properly test the angle and avoid standing on slopes
+ Vector3 horizontal_motion = motion.slide(up_direction);
+ Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized();
+ real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(horizontal_motion.normalized())));
+
+ // Avoid to move forward on a wall if floor_block_on_wall is true.
+ // Applies only when the motion angle is under 90 degrees,
+ // in order to avoid blocking lateral motion along a wall.
+ if (motion_angle < .5 * Math_PI) {
+ apply_default_sliding = false;
+
+ if (p_was_on_floor && !vel_dir_facing_up) {
+ // Cancel the motion.
+ Transform3D gt = get_global_transform();
+ real_t travel_total = result.travel.length();
+ real_t cancel_dist_max = MIN(0.1, margin * 20);
+ if (travel_total <= margin + CMP_EPSILON) {
+ gt.origin -= result.travel;
+ } else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls.
+ gt.origin -= result.travel.slide(up_direction);
+ // Keep remaining motion in sync with amount canceled.
+ motion = motion.slide(up_direction);
+ }
+ set_global_transform(gt);
+ result.travel = Vector3(); // Cancel for constant speed computation.
+
+ // 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.
+ motion = result.remainder;
+ }
+
+ // Apply slide on forward in order to allow only lateral motion on next step.
+ Vector3 forward = wall_normal.slide(up_direction).normalized();
+ motion = motion.slide(forward);
+ // Avoid accelerating when you jump on the wall and smooth falling.
+ linear_velocity = linear_velocity.slide(forward);
+
+ // Allow only lateral motion along previous floor when already on floor.
+ // Fixes slowing down when moving in diagonal against an inclined wall.
+ if (p_was_on_floor && !vel_dir_facing_up && (motion.dot(up_direction) > 0.0)) {
+ // Slide along the corner between the wall and previous floor.
+ Vector3 floor_side = prev_floor_normal.cross(wall_normal);
+ if (floor_side != Vector3()) {
+ motion = floor_side * motion.dot(floor_side);
+ }
+ }
+
+ // Stop all motion when a second wall is hit (unless sliding down or jumping),
+ // in order to avoid jittering in corner cases.
+ bool stop_all_motion = previous_state.wall && !vel_dir_facing_up;
+
+ // Allow sliding when the body falls.
+ if (!collision_state.floor && motion.dot(up_direction) < 0) {
+ Vector3 slide_motion = motion.slide(wall_normal);
+ // Test again to allow sliding only if the result goes downwards.
+ // Fixes jittering issues at the bottom of inclined walls.
+ if (slide_motion.dot(up_direction) < 0) {
+ stop_all_motion = false;
+ motion = slide_motion;
+ }
+ }
+
+ if (stop_all_motion) {
+ motion = Vector3();
+ linear_velocity = Vector3();
+ }
+ }
}
- } else {
- motion = result.remainder;
+
+ // Stop horizontal motion when under wall slide threshold.
+ if (p_was_on_floor && (wall_min_slide_angle > 0.0) && result_state.wall) {
+ Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized();
+ real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized())));
+ if (motion_angle < wall_min_slide_angle) {
+ motion = up_direction * motion.dot(up_direction);
+ linear_velocity = up_direction * linear_velocity.dot(up_direction);
+
+ apply_default_sliding = false;
+ }
+ }
+ }
+
+ if (apply_default_sliding) {
+ // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling.
+ if ((sliding_enabled || !collision_state.floor) && (!collision_state.ceiling || slide_on_ceiling || !vel_dir_facing_up)) {
+ const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
+ Vector3 slide_motion = result.remainder.slide(collision.normal);
+ if (slide_motion.dot(linear_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector3();
+ }
+ if (slide_on_ceiling && result_state.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) {
+ linear_velocity = linear_velocity.slide(collision.normal);
+ } else {
+ // Avoid acceleration in slope when falling.
+ linear_velocity = up_direction * up_direction.dot(linear_velocity);
+ }
+ }
+ }
+ // No sliding on first attempt to keep floor motion stable when possible.
+ else {
+ motion = result.remainder;
+ if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ motion = motion.slide(up_direction);
+ }
+ }
+ }
+
+ // Apply Constant Speed.
+ if (p_was_on_floor && floor_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) {
+ motion = motion.normalized() * MAX(0, (motion_slide_up.length() - result.travel.slide(up_direction).length() - total_travel.slide(up_direction).length()));
}
+
+ total_travel += result.travel;
+ }
+ // When you move forward in a downward slope you don’t collide because you will be in the air.
+ // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied.
+ else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) {
+ can_apply_constant_speed = false;
+ sliding_enabled = true;
+ Transform3D gt = get_global_transform();
+ gt.origin = gt.origin - result.travel;
+ set_global_transform(gt);
+
+ Vector3 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
+ motion = motion_slide_norm * (motion_slide_up.length());
+ collided = true;
}
+ can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
sliding_enabled = true;
+ first_slide = false;
+
+ if (!motion.is_equal_approx(Vector3())) {
+ last_motion = motion;
+ }
if (!collided || motion.is_equal_approx(Vector3())) {
break;
}
}
- if (was_on_floor && !on_floor && !snap.is_equal_approx(Vector3())) {
- // Apply snap.
- Transform3D gt = get_global_transform();
+ _snap_on_floor(p_was_on_floor, vel_dir_facing_up);
+
+ // Reset the gravity accumulation when touching the ground.
+ if (collision_state.floor && !vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ }
+}
+
+void CharacterBody3D::_move_and_slide_free(double p_delta) {
+ Vector3 motion = linear_velocity * p_delta;
+
+ platform_rid = RID();
+ floor_normal = Vector3();
+ platform_velocity = Vector3();
+
+ bool first_slide = true;
+ for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionResult result;
- if (move_and_collide(snap, result, margin, true, false, true)) {
- bool apply = true;
- if (up_direction != Vector3()) {
- if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
- on_floor = true;
- floor_normal = result.collision_normal;
- on_floor_body = result.collider;
- floor_velocity = result.collider_velocity;
- if (floor_stop_on_slope) {
- // move and collide may stray the object a bit because of pre un-stucking,
- // so only ensure that motion happens on floor direction in this case.
- if (result.travel.length() > margin) {
- result.travel = result.travel.project(up_direction);
- } else {
- result.travel = Vector3();
- }
- }
- } else {
- apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
+
+ bool collided = move_and_collide(motion, result, margin, false, 1, false);
+
+ if (collided) {
+ motion_results.push_back(result);
+
+ CollisionState result_state;
+ _set_collision_direction(result, result_state);
+
+ if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-linear_velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) {
+ motion = Vector3();
+ if (result.travel.length() < margin + CMP_EPSILON) {
+ Transform3D gt = get_global_transform();
+ gt.origin -= result.travel;
+ set_global_transform(gt);
}
+ } else if (first_slide) {
+ Vector3 motion_slide_norm = result.remainder.slide(wall_normal).normalized();
+ motion = motion_slide_norm * (motion.length() - result.travel.length());
+ } else {
+ motion = result.remainder.slide(wall_normal);
}
- if (apply) {
- gt.origin += result.travel;
- set_global_transform(gt);
+
+ if (motion.dot(linear_velocity) <= 0.0) {
+ motion = Vector3();
}
}
+
+ first_slide = false;
+
+ if (!collided || motion.is_equal_approx(Vector3())) {
+ break;
+ }
}
+}
- if (!on_floor && !on_wall) {
- // Add last platform velocity when just left a moving platform.
- linear_velocity += current_floor_velocity;
+void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) {
+ if (collision_state.floor || !was_on_floor || vel_dir_facing_up) {
+ return;
}
- // Reset the gravity accumulation when touching the ground.
- if (on_floor && linear_velocity.dot(up_direction) <= 0) {
- linear_velocity = linear_velocity.slide(up_direction);
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
+
+ Transform3D gt = get_global_transform();
+ PhysicsServer3D::MotionResult result;
+ if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) {
+ CollisionState result_state;
+ // Apply direction for floor only.
+ _set_collision_direction(result, result_state, CollisionState(true, false, false));
+
+ if (result_state.floor) {
+ if (floor_stop_on_slope) {
+ // move and collide may stray the object a bit because of pre un-stucking,
+ // so only ensure that motion happens on floor direction in this case.
+ if (result.travel.length() > margin) {
+ result.travel = up_direction * up_direction.dot(result.travel);
+ } else {
+ result.travel = Vector3();
+ }
+ }
+
+ gt.origin += result.travel;
+ set_global_transform(gt);
+ }
}
+}
- return motion_results.size() > 0;
+bool CharacterBody3D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) {
+ if (up_direction == Vector3() || collision_state.floor || !was_on_floor || vel_dir_facing_up) {
+ return false;
+ }
+
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
+
+ PhysicsServer3D::MotionResult result;
+ if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) {
+ CollisionState result_state;
+ // Don't apply direction for any type.
+ _set_collision_direction(result, result_state, CollisionState());
+
+ return result_state.floor;
+ }
+
+ return false;
}
-void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result) {
- if (up_direction == Vector3()) {
- //all is a wall
- on_wall = true;
- } else {
- if (p_result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
- on_floor = true;
- floor_normal = p_result.collision_normal;
- on_floor_body = p_result.collider;
- floor_velocity = p_result.collider_velocity;
- } else if (p_result.get_angle(-up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
- on_ceiling = true;
- } else {
- on_wall = true;
+void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state) {
+ r_state.state = 0;
+
+ real_t wall_depth = -1.0;
+ real_t floor_depth = -1.0;
+
+ bool was_on_wall = collision_state.wall;
+ Vector3 prev_wall_normal = wall_normal;
+ int wall_collision_count = 0;
+ Vector3 combined_wall_normal;
+
+ for (int i = p_result.collision_count - 1; i >= 0; i--) {
+ const PhysicsServer3D::MotionCollision &collision = p_result.collisions[i];
+
+ if (motion_mode == MOTION_MODE_GROUNDED) {
+ // Check if any collision is floor.
+ real_t floor_angle = collision.get_angle(up_direction);
+ if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ r_state.floor = true;
+ if (p_apply_state.floor && collision.depth > floor_depth) {
+ collision_state.floor = true;
+ floor_normal = collision.normal;
+ floor_depth = collision.depth;
+ _set_platform_data(collision);
+ }
+ continue;
+ }
+
+ // Check if any collision is ceiling.
+ real_t ceiling_angle = collision.get_angle(-up_direction);
+ if (ceiling_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ r_state.ceiling = true;
+ if (p_apply_state.ceiling) {
+ collision_state.ceiling = true;
+ }
+ continue;
+ }
+ }
+
+ // Collision is wall by default.
+ r_state.wall = true;
+
+ if (p_apply_state.wall && collision.depth > wall_depth) {
+ collision_state.wall = true;
+ wall_depth = collision.depth;
+ wall_normal = collision.normal;
+
// Don't apply wall velocity when the collider is a CharacterBody3D.
- if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) {
- on_floor_body = p_result.collider;
- floor_velocity = p_result.collider_velocity;
+ if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(collision.collider_id)) == nullptr) {
+ _set_platform_data(collision);
}
}
+
+ // Collect normal for calculating average.
+ combined_wall_normal += collision.normal;
+ wall_collision_count++;
}
+
+ if (r_state.wall) {
+ if (wall_collision_count > 1 && !r_state.floor) {
+ // Check if wall normals cancel out to floor support.
+ if (!r_state.floor && motion_mode == MOTION_MODE_GROUNDED) {
+ combined_wall_normal.normalize();
+ real_t floor_angle = Math::acos(combined_wall_normal.dot(up_direction));
+ if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ r_state.floor = true;
+ r_state.wall = false;
+ if (p_apply_state.floor) {
+ collision_state.floor = true;
+ floor_normal = combined_wall_normal;
+ }
+ if (p_apply_state.wall) {
+ collision_state.wall = was_on_wall;
+ wall_normal = prev_wall_normal;
+ }
+ return;
+ }
+ }
+ }
+ }
+}
+
+void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision &p_collision) {
+ platform_rid = p_collision.collider;
+ platform_velocity = p_collision.collider_velocity;
+ platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid);
}
void CharacterBody3D::set_safe_margin(real_t p_margin) {
@@ -1212,40 +1573,56 @@ void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) {
}
bool CharacterBody3D::is_on_floor() const {
- return on_floor;
+ return collision_state.floor;
}
bool CharacterBody3D::is_on_floor_only() const {
- return on_floor && !on_wall && !on_ceiling;
+ return collision_state.floor && !collision_state.wall && !collision_state.ceiling;
}
bool CharacterBody3D::is_on_wall() const {
- return on_wall;
+ return collision_state.wall;
}
bool CharacterBody3D::is_on_wall_only() const {
- return on_wall && !on_floor && !on_ceiling;
+ return collision_state.wall && !collision_state.floor && !collision_state.ceiling;
}
bool CharacterBody3D::is_on_ceiling() const {
- return on_ceiling;
+ return collision_state.ceiling;
}
bool CharacterBody3D::is_on_ceiling_only() const {
- return on_ceiling && !on_floor && !on_wall;
+ return collision_state.ceiling && !collision_state.floor && !collision_state.wall;
}
Vector3 CharacterBody3D::get_floor_normal() const {
return floor_normal;
}
+Vector3 CharacterBody3D::get_wall_normal() const {
+ return wall_normal;
+}
+
+Vector3 CharacterBody3D::get_last_motion() const {
+ return last_motion;
+}
+
+Vector3 CharacterBody3D::get_position_delta() const {
+ return get_transform().origin - previous_position;
+}
+
+Vector3 CharacterBody3D::get_real_velocity() const {
+ return real_velocity;
+};
+
real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const {
ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
return Math::acos(floor_normal.dot(p_up_direction));
}
Vector3 CharacterBody3D::get_platform_velocity() const {
- return floor_velocity;
+ return platform_velocity;
}
int CharacterBody3D::get_slide_collision_count() const {
@@ -1263,7 +1640,8 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
slide_colliders.resize(p_bounce + 1);
}
- if (slide_colliders[p_bounce].is_null()) {
+ // Create a new instance when the cached reference is invalid or still in use in script.
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
@@ -1287,6 +1665,62 @@ void CharacterBody3D::set_floor_stop_on_slope_enabled(bool p_enabled) {
floor_stop_on_slope = p_enabled;
}
+bool CharacterBody3D::is_floor_constant_speed_enabled() const {
+ return floor_constant_speed;
+}
+
+void CharacterBody3D::set_floor_constant_speed_enabled(bool p_enabled) {
+ floor_constant_speed = p_enabled;
+}
+
+bool CharacterBody3D::is_floor_block_on_wall_enabled() const {
+ return floor_block_on_wall;
+}
+
+void CharacterBody3D::set_floor_block_on_wall_enabled(bool p_enabled) {
+ floor_block_on_wall = p_enabled;
+}
+
+bool CharacterBody3D::is_slide_on_ceiling_enabled() const {
+ return slide_on_ceiling;
+}
+
+void CharacterBody3D::set_slide_on_ceiling_enabled(bool p_enabled) {
+ slide_on_ceiling = p_enabled;
+}
+
+uint32_t CharacterBody3D::get_moving_platform_floor_layers() const {
+ return moving_platform_floor_layers;
+}
+
+void CharacterBody3D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) {
+ moving_platform_floor_layers = p_exclude_layers;
+}
+
+uint32_t CharacterBody3D::get_moving_platform_wall_layers() const {
+ return moving_platform_wall_layers;
+}
+
+void CharacterBody3D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
+ moving_platform_wall_layers = p_exclude_layers;
+}
+
+void CharacterBody3D::set_motion_mode(MotionMode p_mode) {
+ motion_mode = p_mode;
+}
+
+CharacterBody3D::MotionMode CharacterBody3D::get_motion_mode() const {
+ return motion_mode;
+}
+
+void CharacterBody3D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) {
+ moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity;
+}
+
+CharacterBody3D::MovingPlatformApplyVelocityOnLeave CharacterBody3D::get_moving_platform_apply_velocity_on_leave() const {
+ return moving_platform_apply_velocity_on_leave;
+}
+
int CharacterBody3D::get_max_slides() const {
return max_slides;
}
@@ -1304,12 +1738,21 @@ void CharacterBody3D::set_floor_max_angle(real_t p_radians) {
floor_max_angle = p_radians;
}
-const Vector3 &CharacterBody3D::get_snap() const {
- return snap;
+real_t CharacterBody3D::get_floor_snap_length() {
+ return floor_snap_length;
}
-void CharacterBody3D::set_snap(const Vector3 &p_snap) {
- snap = p_snap;
+void CharacterBody3D::set_floor_snap_length(real_t p_floor_snap_length) {
+ ERR_FAIL_COND(p_floor_snap_length < 0);
+ floor_snap_length = p_floor_snap_length;
+}
+
+real_t CharacterBody3D::get_wall_min_slide_angle() const {
+ return wall_min_slide_angle;
+}
+
+void CharacterBody3D::set_wall_min_slide_angle(real_t p_radians) {
+ wall_min_slide_angle = p_radians;
}
const Vector3 &CharacterBody3D::get_up_direction() const {
@@ -1317,6 +1760,7 @@ const Vector3 &CharacterBody3D::get_up_direction() const {
}
void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) {
+ ERR_FAIL_COND_MSG(p_up_direction == Vector3(), "up_direction can't be equal to Vector3.ZERO, consider using Free motion mode instead.");
up_direction = p_up_direction.normalized();
}
@@ -1324,12 +1768,10 @@ void CharacterBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
// Reset move_and_slide() data.
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
+ collision_state.state = 0;
+ platform_rid = RID();
motion_results.clear();
- floor_velocity = Vector3();
+ platform_velocity = Vector3();
} break;
}
}
@@ -1344,14 +1786,32 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody3D::set_floor_constant_speed_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody3D::is_floor_constant_speed_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody3D::set_floor_block_on_wall_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody3D::is_floor_block_on_wall_enabled);
+ ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody3D::set_slide_on_ceiling_enabled);
+ ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody3D::is_slide_on_ceiling_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody3D::get_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody3D::get_moving_platform_wall_layers);
+
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides);
ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle);
ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle);
- ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody3D::get_snap);
- ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody3D::set_snap);
+ ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody3D::get_floor_snap_length);
+ ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody3D::set_floor_snap_length);
+ ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody3D::get_wall_min_slide_angle);
+ ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody3D::set_wall_min_slide_angle);
ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction);
ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction);
+ ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody3D::set_motion_mode);
+ ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody3D::get_motion_mode);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_moving_platform_apply_velocity_on_leave);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody3D::get_moving_platform_apply_velocity_on_leave);
ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor);
ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only);
@@ -1360,21 +1820,49 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall);
ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody3D::is_on_wall_only);
ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal);
+ ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody3D::get_wall_normal);
+ ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody3D::get_last_motion);
+ ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody3D::get_position_delta);
+ ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody3D::get_real_velocity);
ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0)));
ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity);
-
ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision);
ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_slides", "get_max_slides");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap"), "set_snap", "get_snap");
+ 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::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_slides", "get_max_slides");
+ ADD_GROUP("Free Mode", "free_mode_");
+ 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::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
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,1,0.01,or_greater"), "set_floor_snap_length", "get_floor_snap_length");
+ ADD_GROUP("Moving platform", "moving_platform");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
+
+ BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
+ BIND_ENUM_CONSTANT(MOTION_MODE_FREE);
+
+ BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS);
+ BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY);
+ BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
+}
+
+void CharacterBody3D::_validate_property(PropertyInfo &property) const {
+ if (motion_mode == MOTION_MODE_FREE) {
+ if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+ }
}
CharacterBody3D::CharacterBody3D() :
@@ -1391,14 +1879,6 @@ CharacterBody3D::~CharacterBody3D() {
///////////////////////////////////////
-Vector3 KinematicCollision3D::get_position() const {
- return result.collision_point;
-}
-
-Vector3 KinematicCollision3D::get_normal() const {
- return result.collision_normal;
-}
-
Vector3 KinematicCollision3D::get_travel() const {
return result.travel;
}
@@ -1407,41 +1887,60 @@ Vector3 KinematicCollision3D::get_remainder() const {
return result.remainder;
}
-real_t KinematicCollision3D::get_angle(const Vector3 &p_up_direction) const {
+int KinematicCollision3D::get_collision_count() const {
+ return result.collision_count;
+}
+
+Vector3 KinematicCollision3D::get_position(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
+ return result.collisions[p_collision_index].position;
+}
+
+Vector3 KinematicCollision3D::get_normal(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
+ return result.collisions[p_collision_index].normal;
+}
+
+real_t KinematicCollision3D::get_angle(int p_collision_index, const Vector3 &p_up_direction) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0);
ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
- return result.get_angle(p_up_direction);
+ return result.collisions[p_collision_index].get_angle(p_up_direction);
}
-Object *KinematicCollision3D::get_local_shape() const {
+Object *KinematicCollision3D::get_local_shape(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr);
if (!owner) {
return nullptr;
}
- uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape);
+ uint32_t ownerid = owner->shape_find_owner(result.collisions[p_collision_index].local_shape);
return owner->shape_owner_get_owner(ownerid);
}
-Object *KinematicCollision3D::get_collider() const {
- if (result.collider_id.is_valid()) {
- return ObjectDB::get_instance(result.collider_id);
+Object *KinematicCollision3D::get_collider(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr);
+ if (result.collisions[p_collision_index].collider_id.is_valid()) {
+ return ObjectDB::get_instance(result.collisions[p_collision_index].collider_id);
}
return nullptr;
}
-ObjectID KinematicCollision3D::get_collider_id() const {
- return result.collider_id;
+ObjectID KinematicCollision3D::get_collider_id(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, ObjectID());
+ return result.collisions[p_collision_index].collider_id;
}
-RID KinematicCollision3D::get_collider_rid() const {
- return result.collider;
+RID KinematicCollision3D::get_collider_rid(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, RID());
+ return result.collisions[p_collision_index].collider;
}
-Object *KinematicCollision3D::get_collider_shape() const {
- Object *collider = get_collider();
+Object *KinematicCollision3D::get_collider_shape(int p_collision_index) const {
+ Object *collider = get_collider(p_collision_index);
if (collider) {
CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider);
if (obj2d) {
- uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape);
+ uint32_t ownerid = obj2d->shape_find_owner(result.collisions[p_collision_index].collider_shape);
return obj2d->shape_owner_get_owner(ownerid);
}
}
@@ -1449,45 +1948,101 @@ Object *KinematicCollision3D::get_collider_shape() const {
return nullptr;
}
-int KinematicCollision3D::get_collider_shape_index() const {
- return result.collider_shape;
+int KinematicCollision3D::get_collider_shape_index(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0);
+ return result.collisions[p_collision_index].collider_shape;
}
-Vector3 KinematicCollision3D::get_collider_velocity() const {
- return result.collider_velocity;
+Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
+ return result.collisions[p_collision_index].collider_velocity;
}
-Variant KinematicCollision3D::get_collider_metadata() const {
+Variant KinematicCollision3D::get_collider_metadata(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Variant());
return Variant();
}
+Vector3 KinematicCollision3D::get_best_position() const {
+ return result.collision_count ? get_position() : Vector3();
+}
+
+Vector3 KinematicCollision3D::get_best_normal() const {
+ return result.collision_count ? get_normal() : Vector3();
+}
+
+Object *KinematicCollision3D::get_best_local_shape() const {
+ return result.collision_count ? get_local_shape() : nullptr;
+}
+
+Object *KinematicCollision3D::get_best_collider() const {
+ return result.collision_count ? get_collider() : nullptr;
+}
+
+ObjectID KinematicCollision3D::get_best_collider_id() const {
+ return result.collision_count ? get_collider_id() : ObjectID();
+}
+
+RID KinematicCollision3D::get_best_collider_rid() const {
+ return result.collision_count ? get_collider_rid() : RID();
+}
+
+Object *KinematicCollision3D::get_best_collider_shape() const {
+ return result.collision_count ? get_collider_shape() : nullptr;
+}
+
+int KinematicCollision3D::get_best_collider_shape_index() const {
+ return result.collision_count ? get_collider_shape_index() : 0;
+}
+
+Vector3 KinematicCollision3D::get_best_collider_velocity() const {
+ return result.collision_count ? get_collider_velocity() : Vector3();
+}
+
+Variant KinematicCollision3D::get_best_collider_metadata() const {
+ return result.collision_count ? get_collider_metadata() : Variant();
+}
+
void KinematicCollision3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision3D::get_position);
- ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision3D::get_normal);
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder);
- ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision3D::get_angle, DEFVAL(Vector3(0.0, 1.0, 0.0)));
- ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision3D::get_local_shape);
- ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision3D::get_collider);
- ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision3D::get_collider_id);
- ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision3D::get_collider_rid);
- ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision3D::get_collider_shape);
- ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision3D::get_collider_shape_index);
- ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision3D::get_collider_velocity);
- ClassDB::bind_method(D_METHOD("get_collider_metadata"), &KinematicCollision3D::get_collider_metadata);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "", "get_normal");
+ ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicCollision3D::get_collision_count);
+ ClassDB::bind_method(D_METHOD("get_position", "collision_index"), &KinematicCollision3D::get_position, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_normal", "collision_index"), &KinematicCollision3D::get_normal, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_angle", "collision_index", "up_direction"), &KinematicCollision3D::get_angle, DEFVAL(0), DEFVAL(Vector3(0.0, 1.0, 0.0)));
+ ClassDB::bind_method(D_METHOD("get_local_shape", "collision_index"), &KinematicCollision3D::get_local_shape, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &KinematicCollision3D::get_collider, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_id", "collision_index"), &KinematicCollision3D::get_collider_id, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &KinematicCollision3D::get_collider_rid, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &KinematicCollision3D::get_collider_shape, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_shape_index", "collision_index"), &KinematicCollision3D::get_collider_shape_index, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &KinematicCollision3D::get_collider_velocity, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_metadata", "collision_index"), &KinematicCollision3D::get_collider_metadata, DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("get_best_position"), &KinematicCollision3D::get_best_position);
+ ClassDB::bind_method(D_METHOD("get_best_normal"), &KinematicCollision3D::get_best_normal);
+ ClassDB::bind_method(D_METHOD("get_best_local_shape"), &KinematicCollision3D::get_best_local_shape);
+ ClassDB::bind_method(D_METHOD("get_best_collider"), &KinematicCollision3D::get_best_collider);
+ ClassDB::bind_method(D_METHOD("get_best_collider_id"), &KinematicCollision3D::get_best_collider_id);
+ ClassDB::bind_method(D_METHOD("get_best_collider_rid"), &KinematicCollision3D::get_best_collider_rid);
+ ClassDB::bind_method(D_METHOD("get_best_collider_shape"), &KinematicCollision3D::get_best_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_best_collider_shape_index"), &KinematicCollision3D::get_best_collider_shape_index);
+ ClassDB::bind_method(D_METHOD("get_best_collider_velocity"), &KinematicCollision3D::get_best_collider_velocity);
+ ClassDB::bind_method(D_METHOD("get_best_collider_metadata"), &KinematicCollision3D::get_best_collider_metadata);
+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id");
- ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_count"), "", "get_collision_count");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "", "get_best_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "", "get_best_normal");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_best_local_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_best_collider");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_best_collider_id");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_best_collider_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_best_collider_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_best_collider_shape_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_best_collider_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_best_collider_metadata");
}
///////////////////////////////////////
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 8e6463f838..a53147cb8f 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0;
- Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001);
+ Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1);
public:
- bool move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>());
- bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
+ bool move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, int p_max_collisions = 1, bool p_cancel_sliding = true, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>());
+ bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
@@ -105,7 +105,7 @@ private:
Vector3 linear_velocity;
Vector3 angular_velocity;
- bool sync_to_physics = false;
+ bool sync_to_physics = true;
Transform3D last_valid_transform;
@@ -129,15 +129,13 @@ private:
bool is_sync_to_physics_enabled() const;
};
-class RigidBody3D : public PhysicsBody3D {
- GDCLASS(RigidBody3D, PhysicsBody3D);
+class RigidDynamicBody3D : public PhysicsBody3D {
+ GDCLASS(RigidDynamicBody3D, PhysicsBody3D);
public:
- enum Mode {
- MODE_DYNAMIC,
- MODE_STATIC,
- MODE_DYNAMIC_LOCKED,
- MODE_KINEMATIC,
+ enum FreezeMode {
+ FREEZE_MODE_STATIC,
+ FREEZE_MODE_KINEMATIC,
};
enum CenterOfMassMode {
@@ -145,11 +143,11 @@ public:
CENTER_OF_MASS_MODE_CUSTOM,
};
- GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
-
-protected:
+private:
bool can_sleep = true;
- Mode mode = MODE_DYNAMIC;
+ bool lock_rotation = false;
+ bool freeze = false;
+ FreezeMode freeze_mode = FREEZE_MODE_STATIC;
real_t mass = 1.0;
Vector3 inertia;
@@ -191,7 +189,7 @@ protected:
tagged = false;
}
};
- struct RigidBody3D_RemoveAction {
+ struct RigidDynamicBody3D_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
@@ -214,16 +212,28 @@ protected:
void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
- virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state);
+protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
+ GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
+
+ virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state);
+
+ void _apply_body_mode();
+
public:
- void set_mode(Mode p_mode);
- Mode get_mode() const;
+ void set_lock_rotation_enabled(bool p_lock_rotation);
+ bool is_lock_rotation_enabled() const;
+
+ void set_freeze_enabled(bool p_freeze);
+ bool is_freeze_enabled() const;
+
+ void set_freeze_mode(FreezeMode p_freeze_mode);
+ FreezeMode get_freeze_mode() const;
void set_mass(real_t p_mass);
real_t get_mass() const;
@@ -291,91 +301,163 @@ public:
virtual TypedArray<String> get_configuration_warnings() const override;
- RigidBody3D();
- ~RigidBody3D();
+ RigidDynamicBody3D();
+ ~RigidDynamicBody3D();
private:
void _reload_physics_characteristics();
};
-VARIANT_ENUM_CAST(RigidBody3D::Mode);
-VARIANT_ENUM_CAST(RigidBody3D::CenterOfMassMode);
+VARIANT_ENUM_CAST(RigidDynamicBody3D::FreezeMode);
+VARIANT_ENUM_CAST(RigidDynamicBody3D::CenterOfMassMode);
class KinematicCollision3D;
class CharacterBody3D : public PhysicsBody3D {
GDCLASS(CharacterBody3D, PhysicsBody3D);
+public:
+ enum MotionMode {
+ MOTION_MODE_GROUNDED,
+ MOTION_MODE_FREE,
+ };
+ enum MovingPlatformApplyVelocityOnLeave {
+ PLATFORM_VEL_ON_LEAVE_ALWAYS,
+ PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
+ PLATFORM_VEL_ON_LEAVE_NEVER,
+ };
+ bool move_and_slide();
+
+ virtual Vector3 get_linear_velocity() const override;
+ void set_linear_velocity(const Vector3 &p_velocity);
+
+ bool is_on_floor() const;
+ bool is_on_floor_only() const;
+ bool is_on_wall() const;
+ bool is_on_wall_only() const;
+ bool is_on_ceiling() const;
+ bool is_on_ceiling_only() const;
+ Vector3 get_last_motion() const;
+ Vector3 get_position_delta() const;
+ Vector3 get_floor_normal() const;
+ Vector3 get_wall_normal() const;
+ Vector3 get_real_velocity() const;
+ real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
+ Vector3 get_platform_velocity() const;
+
+ int get_slide_collision_count() const;
+ PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
+
+ CharacterBody3D();
+ ~CharacterBody3D();
+
private:
real_t margin = 0.001;
+ MotionMode motion_mode = MOTION_MODE_GROUNDED;
+ MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
+ union CollisionState {
+ uint32_t state = 0;
+ struct {
+ bool floor;
+ bool wall;
+ bool ceiling;
+ };
+
+ CollisionState() {
+ }
+
+ CollisionState(bool p_floor, bool p_wall, bool p_ceiling) {
+ floor = p_floor;
+ wall = p_wall;
+ ceiling = p_ceiling;
+ }
+ };
- bool floor_stop_on_slope = false;
- int max_slides = 4;
+ CollisionState collision_state;
+ bool floor_constant_speed = false;
+ bool floor_stop_on_slope = true;
+ bool floor_block_on_wall = true;
+ bool slide_on_ceiling = true;
+ int max_slides = 6;
+ int platform_layer;
+ RID platform_rid;
+ uint32_t moving_platform_floor_layers = UINT32_MAX;
+ uint32_t moving_platform_wall_layers = 0;
+ real_t floor_snap_length = 0.1;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
- Vector3 snap;
+ real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
-
Vector3 linear_velocity;
-
Vector3 floor_normal;
- Vector3 floor_velocity;
- RID on_floor_body;
- bool on_floor = false;
- bool on_ceiling = false;
- bool on_wall = false;
+ Vector3 wall_normal;
+ Vector3 last_motion;
+ Vector3 platform_velocity;
+ Vector3 previous_position;
+ Vector3 real_velocity;
+
Vector<PhysicsServer3D::MotionResult> motion_results;
Vector<Ref<KinematicCollision3D>> slide_colliders;
- Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
- Ref<KinematicCollision3D> _get_last_slide_collision();
-
- void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result);
-
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
bool is_floor_stop_on_slope_enabled() const;
void set_floor_stop_on_slope_enabled(bool p_enabled);
+ bool is_floor_constant_speed_enabled() const;
+ void set_floor_constant_speed_enabled(bool p_enabled);
+
+ bool is_floor_block_on_wall_enabled() const;
+ void set_floor_block_on_wall_enabled(bool p_enabled);
+
+ bool is_slide_on_ceiling_enabled() const;
+ void set_slide_on_ceiling_enabled(bool p_enabled);
+
int get_max_slides() const;
void set_max_slides(int p_max_slides);
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
- const Vector3 &get_snap() const;
- void set_snap(const Vector3 &p_snap);
+ real_t get_floor_snap_length();
+ void set_floor_snap_length(real_t p_floor_snap_length);
- const Vector3 &get_up_direction() const;
- void set_up_direction(const Vector3 &p_up_direction);
+ real_t get_wall_min_slide_angle() const;
+ void set_wall_min_slide_angle(real_t p_radians);
-protected:
- void _notification(int p_what);
- static void _bind_methods();
+ uint32_t get_moving_platform_floor_layers() const;
+ void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
-public:
- bool move_and_slide();
+ uint32_t get_moving_platform_wall_layers() const;
+ void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
- virtual Vector3 get_linear_velocity() const override;
- void set_linear_velocity(const Vector3 &p_velocity);
+ void set_motion_mode(MotionMode p_mode);
+ MotionMode get_motion_mode() const;
- bool is_on_floor() const;
- bool is_on_floor_only() const;
- bool is_on_wall() const;
- bool is_on_wall_only() const;
- bool is_on_ceiling() const;
- bool is_on_ceiling_only() const;
- Vector3 get_floor_normal() const;
- real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
- Vector3 get_platform_velocity() const;
+ void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
+ MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
- int get_slide_collision_count() const;
- PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
+ void _move_and_slide_free(double p_delta);
+ void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
- CharacterBody3D();
- ~CharacterBody3D();
+ Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
+ Ref<KinematicCollision3D> _get_last_slide_collision();
+ const Vector3 &get_up_direction() const;
+ bool _on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up);
+ void set_up_direction(const Vector3 &p_up_direction);
+ void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state = CollisionState(true, true, true));
+ void _set_platform_data(const PhysicsServer3D::MotionCollision &p_collision);
+ void _snap_on_floor(bool was_on_floor, bool vel_dir_facing_up);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
};
+VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
+VARIANT_ENUM_CAST(CharacterBody3D::MovingPlatformApplyVelocityOnLeave);
+
class KinematicCollision3D : public RefCounted {
GDCLASS(KinematicCollision3D, RefCounted);
@@ -388,19 +470,31 @@ protected:
static void _bind_methods();
public:
- Vector3 get_position() const;
- Vector3 get_normal() const;
Vector3 get_travel() const;
Vector3 get_remainder() const;
- real_t get_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
- Object *get_local_shape() const;
- Object *get_collider() const;
- ObjectID get_collider_id() const;
- RID get_collider_rid() const;
- Object *get_collider_shape() const;
- int get_collider_shape_index() const;
- Vector3 get_collider_velocity() const;
- Variant get_collider_metadata() const;
+ int get_collision_count() const;
+ Vector3 get_position(int p_collision_index = 0) const;
+ Vector3 get_normal(int p_collision_index = 0) const;
+ real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
+ Object *get_local_shape(int p_collision_index = 0) const;
+ Object *get_collider(int p_collision_index = 0) const;
+ ObjectID get_collider_id(int p_collision_index = 0) const;
+ RID get_collider_rid(int p_collision_index = 0) const;
+ Object *get_collider_shape(int p_collision_index = 0) const;
+ int get_collider_shape_index(int p_collision_index = 0) const;
+ Vector3 get_collider_velocity(int p_collision_index = 0) const;
+ Variant get_collider_metadata(int p_collision_index = 0) const;
+
+ Vector3 get_best_position() const;
+ Vector3 get_best_normal() const;
+ Object *get_best_local_shape() const;
+ Object *get_best_collider() const;
+ ObjectID get_best_collider_id() const;
+ RID get_best_collider_rid() const;
+ Object *get_best_collider_shape() const;
+ int get_best_collider_shape_index() const;
+ Vector3 get_best_collider_velocity() const;
+ Variant get_best_collider_metadata() const;
};
class PhysicalBone3D : public PhysicsBody3D {
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 0f5de621ea..b7a79a2645 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -520,6 +520,7 @@ void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
+ ERR_FAIL_COND(p_bone == p_parent);
bones.write[p_bone].parent = p_parent;
process_order_dirty = true;
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 466f67afb8..8d90aabfac 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -99,7 +99,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
child_ci->current_pos = child_ci->initial_transform.origin;
if (child_ci->parent_item) {
- child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length();
+ child_ci->length = child_ci->parent_item->current_pos.distance_to(child_ci->current_pos);
}
}
@@ -140,7 +140,7 @@ void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet, Vec
solve_simple_backwards(p_task->chain, p_solve_magnet);
solve_simple_forwards(p_task->chain, p_solve_magnet, p_origin_pos);
- distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length();
+ distance_to_goal = p_task->chain.tips[0].end_effector->goal_transform.origin.distance_to(p_task->chain.tips[0].chain_item->current_pos);
}
}
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp
index 7eb189e890..a886c61263 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_dynamic_body_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* soft_body_3d.cpp */
+/* soft_dynamic_body_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "soft_body_3d.h"
+#include "soft_dynamic_body_3d.h"
#include "scene/3d/physics_body_3d.h"
-SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
+SoftDynamicBodyRenderingServerHandler::SoftDynamicBodyRenderingServerHandler() {}
-void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
+void SoftDynamicBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
clear();
ERR_FAIL_COND(!p_mesh.is_valid());
@@ -56,7 +56,7 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
}
-void SoftBodyRenderingServerHandler::clear() {
+void SoftDynamicBodyRenderingServerHandler::clear() {
buffer.resize(0);
stride = 0;
offset_vertices = 0;
@@ -66,41 +66,41 @@ void SoftBodyRenderingServerHandler::clear() {
mesh = RID();
}
-void SoftBodyRenderingServerHandler::open() {
+void SoftDynamicBodyRenderingServerHandler::open() {
write_buffer = buffer.ptrw();
}
-void SoftBodyRenderingServerHandler::close() {
+void SoftDynamicBodyRenderingServerHandler::close() {
write_buffer = nullptr;
}
-void SoftBodyRenderingServerHandler::commit_changes() {
+void SoftDynamicBodyRenderingServerHandler::commit_changes() {
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
}
-void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
+void SoftDynamicBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
-void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
+void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
}
-void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
+void SoftDynamicBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
}
-SoftBody3D::PinnedPoint::PinnedPoint() {
+SoftDynamicBody3D::PinnedPoint::PinnedPoint() {
}
-SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
+SoftDynamicBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
point_index = obj_tocopy.point_index;
spatial_attachment_path = obj_tocopy.spatial_attachment_path;
spatial_attachment = obj_tocopy.spatial_attachment;
offset = obj_tocopy.offset;
}
-SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
+SoftDynamicBody3D::PinnedPoint &SoftDynamicBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
@@ -108,7 +108,7 @@ SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &o
return *this;
}
-void SoftBody3D::_update_pickable() {
+void SoftDynamicBody3D::_update_pickable() {
if (!is_inside_tree()) {
return;
}
@@ -116,7 +116,7 @@ void SoftBody3D::_update_pickable() {
PhysicsServer3D::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
-bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
+bool SoftDynamicBody3D::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
String which = name.get_slicec('/', 0);
@@ -133,7 +133,7 @@ bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
-bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
+bool SoftDynamicBody3D::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
String which = name.get_slicec('/', 0);
@@ -160,7 +160,7 @@ bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
-void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
+void SoftDynamicBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
const int pinned_points_indices_size = pinned_points.size();
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "pinned_points"));
@@ -172,7 +172,7 @@ void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
+bool SoftDynamicBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
const int p_indices_size = p_indices.size();
{ // Remove the pined points on physics server that will be removed by resize
@@ -201,7 +201,7 @@ bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
return true;
}
-bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
+bool SoftDynamicBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
if (pinned_points.size() <= p_item) {
return false;
}
@@ -220,7 +220,7 @@ bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String
return true;
}
-bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
+bool SoftDynamicBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
if (pinned_points.size() <= p_item) {
return false;
}
@@ -239,15 +239,7 @@ bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, V
return true;
}
-void SoftBody3D::_softbody_changed() {
- prepare_physics_server();
- _reset_points_offsets();
-#ifdef TOOLS_ENABLED
- update_configuration_warnings();
-#endif
-}
-
-void SoftBody3D::_notification(int p_what) {
+void SoftDynamicBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
if (Engine::get_singleton()->is_editor_hint()) {
@@ -312,56 +304,56 @@ void SoftBody3D::_notification(int p_what) {
}
}
-void SoftBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid);
+void SoftDynamicBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftDynamicBody3D::get_physics_rid);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftDynamicBody3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftDynamicBody3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody3D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftDynamicBody3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftDynamicBody3D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftBody3D::set_collision_mask_value);
- ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftBody3D::get_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftDynamicBody3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftDynamicBody3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftBody3D::set_collision_layer_value);
- ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftBody3D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftDynamicBody3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftDynamicBody3D::get_collision_layer_value);
- ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftDynamicBody3D::set_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftDynamicBody3D::get_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftBody3D::set_disable_mode);
- ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftBody3D::get_disable_mode);
+ ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftDynamicBody3D::set_disable_mode);
+ ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftDynamicBody3D::get_disable_mode);
- ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions);
- ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with);
- ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftDynamicBody3D::get_collision_exceptions);
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftDynamicBody3D::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftDynamicBody3D::remove_collision_exception_with);
- ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody3D::set_simulation_precision);
- ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody3D::get_simulation_precision);
+ ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftDynamicBody3D::set_simulation_precision);
+ ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftDynamicBody3D::get_simulation_precision);
- ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody3D::set_total_mass);
- ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody3D::get_total_mass);
+ ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftDynamicBody3D::set_total_mass);
+ ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftDynamicBody3D::get_total_mass);
- ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness);
- ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftDynamicBody3D::set_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftDynamicBody3D::get_linear_stiffness);
- ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftDynamicBody3D::set_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftDynamicBody3D::get_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient);
- ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftDynamicBody3D::set_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftDynamicBody3D::get_damping_coefficient);
- ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody3D::set_drag_coefficient);
- ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody3D::get_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftDynamicBody3D::set_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftDynamicBody3D::get_drag_coefficient);
- ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftBody3D::get_point_transform);
+ ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftDynamicBody3D::get_point_transform);
- ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftBody3D::pin_point, DEFVAL(NodePath()));
- ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftBody3D::is_point_pinned);
+ ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftDynamicBody3D::pin_point, DEFVAL(NodePath()));
+ ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftDynamicBody3D::is_point_pinned);
- ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody3D::set_ray_pickable);
- ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody3D::is_ray_pickable);
+ ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftDynamicBody3D::set_ray_pickable);
+ ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftDynamicBody3D::is_ray_pickable);
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
@@ -383,7 +375,7 @@ void SoftBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
-TypedArray<String> SoftBody3D::get_configuration_warnings() const {
+TypedArray<String> SoftDynamicBody3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (get_mesh().is_null()) {
@@ -392,13 +384,13 @@ TypedArray<String> SoftBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ warnings.push_back(TTR("Size changes to SoftDynamicBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void SoftBody3D::_update_physics_server() {
+void SoftDynamicBody3D::_update_physics_server() {
if (!simulation_started) {
return;
}
@@ -414,7 +406,7 @@ void SoftBody3D::_update_physics_server() {
}
}
-void SoftBody3D::_draw_soft_mesh() {
+void SoftDynamicBody3D::_draw_soft_mesh() {
if (get_mesh().is_null()) {
return;
}
@@ -437,7 +429,7 @@ void SoftBody3D::_draw_soft_mesh() {
rendering_server_handler.commit_changes();
}
-void SoftBody3D::prepare_physics_server() {
+void SoftDynamicBody3D::prepare_physics_server() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (get_mesh().is_valid()) {
@@ -453,16 +445,16 @@ void SoftBody3D::prepare_physics_server() {
if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) {
become_mesh_owner();
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
- RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
+ RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
} else {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
- if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh))) {
- RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
+ if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh))) {
+ RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
}
}
}
-void SoftBody3D::become_mesh_owner() {
+void SoftDynamicBody3D::become_mesh_owner() {
if (mesh.is_null()) {
return;
}
@@ -475,7 +467,7 @@ void SoftBody3D::become_mesh_owner() {
ERR_FAIL_COND(!mesh->get_surface_count());
- // Get current mesh array and create new mesh array with necessary flag for softbody
+ // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody
Array surface_arrays = mesh->surface_get_arrays(0);
Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
Dictionary surface_lods = mesh->surface_get_lods(0);
@@ -496,25 +488,25 @@ void SoftBody3D::become_mesh_owner() {
}
}
-void SoftBody3D::set_collision_mask(uint32_t p_mask) {
+void SoftDynamicBody3D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
PhysicsServer3D::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
}
-uint32_t SoftBody3D::get_collision_mask() const {
+uint32_t SoftDynamicBody3D::get_collision_mask() const {
return collision_mask;
}
-void SoftBody3D::set_collision_layer(uint32_t p_layer) {
+void SoftDynamicBody3D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
PhysicsServer3D::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
}
-uint32_t SoftBody3D::get_collision_layer() const {
+uint32_t SoftDynamicBody3D::get_collision_layer() const {
return collision_layer;
}
-void SoftBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+void SoftDynamicBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer = get_collision_layer();
@@ -526,13 +518,13 @@ void SoftBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
set_collision_layer(collision_layer);
}
-bool SoftBody3D::get_collision_layer_value(int p_layer_number) const {
+bool SoftDynamicBody3D::get_collision_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void SoftBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+void SoftDynamicBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
@@ -544,13 +536,13 @@ void SoftBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
set_collision_mask(mask);
}
-bool SoftBody3D::get_collision_mask_value(int p_layer_number) const {
+bool SoftDynamicBody3D::get_collision_mask_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
return get_collision_mask() & (1 << (p_layer_number - 1));
}
-void SoftBody3D::set_disable_mode(DisableMode p_mode) {
+void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
}
@@ -568,30 +560,30 @@ void SoftBody3D::set_disable_mode(DisableMode p_mode) {
}
}
-SoftBody3D::DisableMode SoftBody3D::get_disable_mode() const {
+SoftDynamicBody3D::DisableMode SoftDynamicBody3D::get_disable_mode() const {
return disable_mode;
}
-void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+void SoftDynamicBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
parent_collision_ignore = p_parent_collision_ignore;
}
-const NodePath &SoftBody3D::get_parent_collision_ignore() const {
+const NodePath &SoftDynamicBody3D::get_parent_collision_ignore() const {
return parent_collision_ignore;
}
-void SoftBody3D::set_pinned_points_indices(Vector<SoftBody3D::PinnedPoint> p_pinned_points_indices) {
+void SoftDynamicBody3D::set_pinned_points_indices(Vector<SoftDynamicBody3D::PinnedPoint> p_pinned_points_indices) {
pinned_points = p_pinned_points_indices;
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
pin_point(p_pinned_points_indices[i].point_index, true);
}
}
-Vector<SoftBody3D::PinnedPoint> SoftBody3D::get_pinned_points_indices() {
+Vector<SoftDynamicBody3D::PinnedPoint> SoftDynamicBody3D::get_pinned_points_indices() {
return pinned_points;
}
-Array SoftBody3D::get_collision_exceptions() {
+Array SoftDynamicBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
Array ret;
@@ -604,77 +596,77 @@ Array SoftBody3D::get_collision_exceptions() {
return ret;
}
-void SoftBody3D::add_collision_exception_with(Node *p_node) {
+void SoftDynamicBody3D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
}
-void SoftBody3D::remove_collision_exception_with(Node *p_node) {
+void SoftDynamicBody3D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
}
-int SoftBody3D::get_simulation_precision() {
+int SoftDynamicBody3D::get_simulation_precision() {
return PhysicsServer3D::get_singleton()->soft_body_get_simulation_precision(physics_rid);
}
-void SoftBody3D::set_simulation_precision(int p_simulation_precision) {
+void SoftDynamicBody3D::set_simulation_precision(int p_simulation_precision) {
PhysicsServer3D::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
}
-real_t SoftBody3D::get_total_mass() {
+real_t SoftDynamicBody3D::get_total_mass() {
return PhysicsServer3D::get_singleton()->soft_body_get_total_mass(physics_rid);
}
-void SoftBody3D::set_total_mass(real_t p_total_mass) {
+void SoftDynamicBody3D::set_total_mass(real_t p_total_mass) {
PhysicsServer3D::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
}
-void SoftBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
+void SoftDynamicBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
PhysicsServer3D::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
}
-real_t SoftBody3D::get_linear_stiffness() {
+real_t SoftDynamicBody3D::get_linear_stiffness() {
return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
-real_t SoftBody3D::get_pressure_coefficient() {
+real_t SoftDynamicBody3D::get_pressure_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
-void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
+void SoftDynamicBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
-real_t SoftBody3D::get_damping_coefficient() {
+real_t SoftDynamicBody3D::get_damping_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
}
-void SoftBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
+void SoftDynamicBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
}
-real_t SoftBody3D::get_drag_coefficient() {
+real_t SoftDynamicBody3D::get_drag_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
}
-void SoftBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
+void SoftDynamicBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
}
-Vector3 SoftBody3D::get_point_transform(int p_point_index) {
+Vector3 SoftDynamicBody3D::get_point_transform(int p_point_index) {
return PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
}
-void SoftBody3D::pin_point_toggle(int p_point_index) {
+void SoftDynamicBody3D::pin_point_toggle(int p_point_index) {
pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
}
-void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
+void SoftDynamicBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
_pin_point_on_physics_server(p_point_index, pin);
if (pin) {
_add_pinned_point(p_point_index, p_spatial_attachment_path);
@@ -683,41 +675,33 @@ void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatia
}
}
-bool SoftBody3D::is_point_pinned(int p_point_index) const {
+bool SoftDynamicBody3D::is_point_pinned(int p_point_index) const {
return -1 != _has_pinned_point(p_point_index);
}
-void SoftBody3D::set_ray_pickable(bool p_ray_pickable) {
+void SoftDynamicBody3D::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
}
-bool SoftBody3D::is_ray_pickable() const {
+bool SoftDynamicBody3D::is_ray_pickable() const {
return ray_pickable;
}
-SoftBody3D::SoftBody3D() :
+SoftDynamicBody3D::SoftDynamicBody3D() :
physics_rid(PhysicsServer3D::get_singleton()->soft_body_create()) {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
}
-SoftBody3D::~SoftBody3D() {
+SoftDynamicBody3D::~SoftDynamicBody3D() {
PhysicsServer3D::get_singleton()->free(physics_rid);
}
-void SoftBody3D::reset_softbody_pin() {
- PhysicsServer3D::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
- const PinnedPoint *pps = pinned_points.ptr();
- for (int i = pinned_points.size() - 1; 0 < i; --i) {
- PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
- }
-}
-
-void SoftBody3D::_make_cache_dirty() {
+void SoftDynamicBody3D::_make_cache_dirty() {
pinned_points_cache_dirty = true;
}
-void SoftBody3D::_update_cache_pin_points_datas() {
+void SoftDynamicBody3D::_update_cache_pin_points_datas() {
if (!pinned_points_cache_dirty) {
return;
}
@@ -730,17 +714,17 @@ void SoftBody3D::_update_cache_pin_points_datas() {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
}
if (!w[i].spatial_attachment) {
- ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftBody3D!");
+ ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftDynamicBody3D!");
}
}
}
-void SoftBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
+void SoftDynamicBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
}
-void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
- SoftBody3D::PinnedPoint *pinned_point;
+void SoftDynamicBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
+ SoftDynamicBody3D::PinnedPoint *pinned_point;
if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
// Create new
PinnedPoint pp;
@@ -765,7 +749,7 @@ void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_
}
}
-void SoftBody3D::_reset_points_offsets() {
+void SoftDynamicBody3D::_reset_points_offsets() {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
@@ -787,25 +771,25 @@ void SoftBody3D::_reset_points_offsets() {
}
}
-void SoftBody3D::_remove_pinned_point(int p_point_index) {
+void SoftDynamicBody3D::_remove_pinned_point(int p_point_index) {
const int id(_has_pinned_point(p_point_index));
if (-1 != id) {
pinned_points.remove(id);
}
}
-int SoftBody3D::_get_pinned_point(int p_point_index, SoftBody3D::PinnedPoint *&r_point) const {
+int SoftDynamicBody3D::_get_pinned_point(int p_point_index, SoftDynamicBody3D::PinnedPoint *&r_point) const {
const int id = _has_pinned_point(p_point_index);
if (-1 == id) {
r_point = nullptr;
return -1;
} else {
- r_point = const_cast<SoftBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
+ r_point = const_cast<SoftDynamicBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
return id;
}
}
-int SoftBody3D::_has_pinned_point(int p_point_index) const {
+int SoftDynamicBody3D::_has_pinned_point(int p_point_index) const {
const PinnedPoint *r = pinned_points.ptr();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (p_point_index == r[i].point_index) {
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_dynamic_body_3d.h
index 46b185a32c..0b4b3021cd 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_dynamic_body_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* soft_body_3d.h */
+/* soft_dynamic_body_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SOFT_PHYSICS_BODY_H
-#define SOFT_PHYSICS_BODY_H
+#ifndef SOFT_DYNAMIC_BODY_H
+#define SOFT_DYNAMIC_BODY_H
#include "scene/3d/mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
-class SoftBody3D;
+class SoftDynamicBody3D;
-class SoftBodyRenderingServerHandler : public RenderingServerHandler {
- friend class SoftBody3D;
+class SoftDynamicBodyRenderingServerHandler : public RenderingServerHandler {
+ friend class SoftDynamicBody3D;
RID mesh;
int surface = 0;
@@ -49,7 +49,7 @@ class SoftBodyRenderingServerHandler : public RenderingServerHandler {
uint8_t *write_buffer = nullptr;
private:
- SoftBodyRenderingServerHandler();
+ SoftDynamicBodyRenderingServerHandler();
bool is_ready() { return mesh.is_valid(); }
void prepare(RID p_mesh_rid, int p_surface);
void clear();
@@ -63,8 +63,8 @@ public:
void set_aabb(const AABB &p_aabb) override;
};
-class SoftBody3D : public MeshInstance3D {
- GDCLASS(SoftBody3D, MeshInstance3D);
+class SoftDynamicBody3D : public MeshInstance3D {
+ GDCLASS(SoftDynamicBody3D, MeshInstance3D);
public:
enum DisableMode {
@@ -84,7 +84,7 @@ public:
};
private:
- SoftBodyRenderingServerHandler rendering_server_handler;
+ SoftDynamicBodyRenderingServerHandler rendering_server_handler;
RID physics_rid;
@@ -106,8 +106,6 @@ private:
void _update_pickable();
- void _softbody_changed();
-
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -184,12 +182,10 @@ public:
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
- SoftBody3D();
- ~SoftBody3D();
+ SoftDynamicBody3D();
+ ~SoftDynamicBody3D();
private:
- void reset_softbody_pin();
-
void _make_cache_dirty();
void _update_cache_pin_points_datas();
@@ -202,6 +198,6 @@ private:
int _has_pinned_point(int p_point_index) const;
};
-VARIANT_ENUM_CAST(SoftBody3D::DisableMode);
+VARIANT_ENUM_CAST(SoftDynamicBody3D::DisableMode);
-#endif // SOFT_PHYSICS_BODY_H
+#endif // SOFT_DYNAMIC_BODY_H
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index daeea81891..9a2aaa8be2 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -470,7 +470,7 @@ real_t VehicleBody3D::_ray_cast(int p_idx, PhysicsDirectBodyState3D *s) {
}
void VehicleBody3D::_update_suspension(PhysicsDirectBodyState3D *s) {
- real_t chassisMass = mass;
+ real_t chassisMass = get_mass();
for (int w_it = 0; w_it < wheels.size(); w_it++) {
VehicleWheel3D &wheel_info = *wheels[w_it];
@@ -558,7 +558,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const
rel_pos2,
normal,
s->get_inverse_inertia_tensor().get_main_diagonal(),
- 1.0 / mass,
+ 1.0 / get_mass(),
b2invinertia,
b2invmass);
@@ -584,7 +584,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const
#define ONLY_USE_LINEAR_MASS
#ifdef ONLY_USE_LINEAR_MASS
- real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
+ real_t massTerm = real_t(1.) / ((1.0 / get_mass()) + b2invmass);
impulse = -contactDamping * rel_vel * massTerm;
#else
real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
@@ -803,7 +803,7 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
}
void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
- RigidBody3D::_body_state_changed(p_state);
+ RigidDynamicBody3D::_body_state_changed(p_state);
real_t step = p_state->get_step();
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index f29c3d89b7..a798c76c1f 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -150,8 +150,8 @@ public:
VehicleWheel3D();
};
-class VehicleBody3D : public RigidBody3D {
- GDCLASS(VehicleBody3D, RigidBody3D);
+class VehicleBody3D : public RigidDynamicBody3D {
+ GDCLASS(VehicleBody3D, RigidDynamicBody3D);
real_t engine_force = 0.0;
real_t brake = 0.0;
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 2d32379d69..04f371f4b2 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -173,7 +173,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
//could not in any way get texture information.. so use closest point to center
Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
- Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
+ Vector3 inters = f.get_closest_point_to(p_aabb.get_center());
Vector3 lnormal;
Vector2 uv;
@@ -434,7 +434,7 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) {
+ if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) {
continue;
}
//plot
@@ -466,7 +466,7 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) {
+ if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) {
continue;
}
//plot face
@@ -885,7 +885,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) {
if (p_level == cell_subdiv - 1) {
- Vector3 center = p_aabb.position + p_aabb.size * 0.5;
+ Vector3 center = p_aabb.get_center();
Transform3D xform;
xform.origin = center;
xform.basis.scale(p_aabb.size * 0.5);
diff --git a/scene/animation/SCsub b/scene/animation/SCsub
index cc33a5af84..d0aa0bc8aa 100644
--- a/scene/animation/SCsub
+++ b/scene/animation/SCsub
@@ -6,11 +6,8 @@ Import("env")
thirdparty_obj = []
-thirdparty_sources = "#thirdparty/misc/easing_equations.cpp"
-
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.scene_sources += thirdparty_obj
# Godot source files
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index d11387902a..af186072ac 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -248,27 +248,26 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek) {
if (fade_in > 0) {
blend = time / fade_in;
} else {
- blend = 0; //wtf
+ blend = 0;
}
-
- } else if (!do_start && remaining < fade_out) {
- if (fade_out) {
+ } else if (!do_start && remaining <= fade_out) {
+ if (fade_out > 0) {
blend = (remaining / fade_out);
} else {
- blend = 1.0;
+ blend = 0;
}
} else {
blend = 1.0;
}
- float main_rem;
+ double main_rem;
if (mix == MIX_MODE_ADD) {
main_rem = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
} else {
main_rem = blend_input(0, p_time, p_seek, 1.0 - blend, FILTER_BLEND, !sync);
}
- float os_rem = blend_input(1, os_seek ? time : p_time, os_seek, blend, FILTER_PASS, false);
+ double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, blend, FILTER_PASS, false);
if (do_start) {
remaining = os_rem;
@@ -718,7 +717,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek) {
} else { // cross-fading from prev to current
- float blend = xfade ? (prev_xfading / xfade) : 1;
+ float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
if (!p_seek && switched) { //just switched, seek to start of current
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index f6091f224c..5825a35030 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -737,7 +737,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (anim->has_loop()) {
at_anim_pos = Math::fposmod(p_time - pos, (double)anim->get_length()); //seek to loop
} else {
- at_anim_pos = MAX((double)anim->get_length(), p_time - pos); //seek to end
+ at_anim_pos = MIN((double)anim->get_length(), p_time - pos); //seek to end
}
if (player->is_playing() || p_seeked) {
@@ -765,6 +765,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
} else {
player->play(anim_name);
+ player->seek(0.0, true);
nc->animation_playing = true;
playing_caches.insert(nc);
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 88fb960164..9ca8d478b1 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -958,7 +958,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
Variant::interpolate(t->value, value, blend, t->value);
- } else if (delta != 0) {
+ } else {
List<int> indices;
a->value_track_get_key_indices(i, time, delta, &indices);
diff --git a/scene/animation/easing_equations.h b/scene/animation/easing_equations.h
new file mode 100644
index 0000000000..c38d083b7f
--- /dev/null
+++ b/scene/animation/easing_equations.h
@@ -0,0 +1,405 @@
+/*************************************************************************/
+/* easing_equations.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+ * Derived from Robert Penner's easing equations: http://robertpenner.com/easing/
+ *
+ * Copyright (c) 2001 Robert Penner
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef EASING_EQUATIONS_H
+#define EASING_EQUATIONS_H
+
+namespace linear {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * t / d + b;
+}
+}; // namespace linear
+
+namespace sine {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return -c * cos(t / d * (Math_PI / 2)) + c + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * sin(t / d * (Math_PI / 2)) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ return -c / 2 * (cos(Math_PI * t / d) - 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace sine
+
+namespace quint {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 5) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * (pow(t / d - 1, 5) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(t, 5) + b;
+ }
+ return c / 2 * (pow(t - 2, 5) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace quint
+
+namespace quart {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 4) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return -c * (pow(t / d - 1, 4) - 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(t, 4) + b;
+ }
+ return -c / 2 * (pow(t - 2, 4) - 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace quart
+
+namespace quad {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 2) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+ return -c * t * (t - 2) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(t, 2) + b;
+ }
+ return -c / 2 * ((t - 1) * (t - 3) - 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace quad
+
+namespace expo {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+ return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == d) {
+ return b + c;
+ }
+ return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ if (t == d) {
+ return b + c;
+ }
+
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005;
+ }
+ return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace expo
+
+namespace elastic {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ t /= d;
+ if (t == 1) {
+ return b + c;
+ }
+
+ t -= 1;
+ float p = d * 0.3f;
+ float a = c * pow(2, 10 * t);
+ float s = p / 4;
+
+ return -(a * sin((t * d - s) * (2 * Math_PI) / p)) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ t /= d;
+ if (t == 1) {
+ return b + c;
+ }
+
+ float p = d * 0.3f;
+ float s = p / 4;
+
+ return (c * pow(2, -10 * t) * sin((t * d - s) * (2 * Math_PI) / p) + c + b);
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ if ((t /= d / 2) == 2) {
+ return b + c;
+ }
+
+ float p = d * (0.3f * 1.5f);
+ float a = c;
+ float s = p / 4;
+
+ if (t < 1) {
+ t -= 1;
+ a *= pow(2, 10 * t);
+ return -0.5f * (a * sin((t * d - s) * (2 * Math_PI) / p)) + b;
+ }
+
+ t -= 1;
+ a *= pow(2, -10 * t);
+ return a * sin((t * d - s) * (2 * Math_PI) / p) * 0.5f + c + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace elastic
+
+namespace cubic {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+ return c * t * t * t + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d - 1;
+ return c * (t * t * t + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d / 2;
+ if (t < 1) {
+ return c / 2 * t * t * t + b;
+ }
+
+ t -= 2;
+ return c / 2 * (t * t * t + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace cubic
+
+namespace circ {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+ return -c * (sqrt(1 - t * t) - 1) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d - 1;
+ return c * sqrt(1 - t * t) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d / 2;
+ if (t < 1) {
+ return -c / 2 * (sqrt(1 - t * t) - 1) + b;
+ }
+
+ t -= 2;
+ return c / 2 * (sqrt(1 - t * t) + 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace circ
+
+namespace bounce {
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+
+ if (t < (1 / 2.75f)) {
+ return c * (7.5625f * t * t) + b;
+ }
+
+ if (t < (2 / 2.75f)) {
+ t -= 1.5f / 2.75f;
+ return c * (7.5625f * t * t + 0.75f) + b;
+ }
+
+ if (t < (2.5 / 2.75)) {
+ t -= 2.25f / 2.75f;
+ return c * (7.5625f * t * t + 0.9375f) + b;
+ }
+
+ t -= 2.625f / 2.75f;
+ return c * (7.5625f * t * t + 0.984375f) + b;
+}
+
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c - out(d - t, 0, c, d) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return in(t * 2, b, c / 2, d);
+ }
+ return out(t * 2 - d, b + c / 2, c / 2, d);
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace bounce
+
+namespace back {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ t /= d;
+
+ return c * t * t * ((s + 1) * t - s) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ t = t / d - 1;
+
+ return c * (t * t * ((s + 1) * t + s) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f * 1.525f;
+ t /= d / 2;
+
+ if (t < 1) {
+ return c / 2 * (t * t * ((s + 1) * t - s)) + b;
+ }
+
+ t -= 2;
+ return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace back
+
+#endif
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 3018fd3ae6..c43b83747b 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -30,8 +30,23 @@
#include "tween.h"
+#include "scene/animation/easing_equations.h"
#include "scene/main/node.h"
+Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
+ { &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
+ { &sine::in, &sine::out, &sine::in_out, &sine::out_in },
+ { &quint::in, &quint::out, &quint::in_out, &quint::out_in },
+ { &quart::in, &quart::out, &quart::in_out, &quart::out_in },
+ { &quad::in, &quad::out, &quad::in_out, &quad::out_in },
+ { &expo::in, &expo::out, &expo::in_out, &expo::out_in },
+ { &elastic::in, &elastic::out, &elastic::in_out, &elastic::out_in },
+ { &cubic::in, &cubic::out, &cubic::in_out, &cubic::out_in },
+ { &circ::in, &circ::out, &circ::in_out, &circ::out_in },
+ { &bounce::in, &bounce::out, &bounce::in_out, &bounce::out_in },
+ { &back::in, &back::out, &back::in_out, &back::out_in },
+};
+
void Tweener::set_tween(Ref<Tween> p_tween) {
tween = p_tween;
}
@@ -60,6 +75,11 @@ Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
+#ifdef DEBUG_ENABLED
+ Variant::Type property_type = p_target->get_indexed(p_property.get_as_property_path().get_subnames()).get_type();
+ ERR_FAIL_COND_V_MSG(property_type != p_to.get_type(), Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type()));
+#endif
+
Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration));
append(tweener);
return tweener;
@@ -83,7 +103,7 @@ Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) {
return tweener;
}
-Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float p_to, float p_duration) {
+Ref<MethodTweener> Tween::tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
@@ -312,6 +332,16 @@ bool Tween::should_pause() {
return pause_mode != TWEEN_PAUSE_PROCESS;
}
+real_t Tween::run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t p_time, real_t p_initial, real_t p_delta, real_t p_duration) {
+ if (p_duration == 0) {
+ // Special case to avoid dividing by 0 in equations.
+ return p_initial + p_delta;
+ }
+
+ interpolater func = interpolaters[p_trans_type][p_ease_type];
+ return func(p_time, p_initial, p_delta, p_duration);
+}
+
Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, TransitionType p_trans, EaseType p_ease) {
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
@@ -496,6 +526,8 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
}
Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) {
+ ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type()));
+
switch (p_intial_val.get_type()) {
case Variant::BOOL: {
return (int)p_final_val - (int)p_intial_val;
@@ -888,7 +920,7 @@ void MethodTweener::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease);
}
-MethodTweener::MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration) {
+MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
callback = p_callback;
initial_val = p_from;
delta_val = tween->calculate_delta_value(p_from, p_to);
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 953d573539..6a48d332b8 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -128,7 +128,7 @@ public:
Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration);
Ref<IntervalTweener> tween_interval(float p_time);
Ref<CallbackTweener> tween_callback(Callable p_callback);
- Ref<MethodTweener> tween_method(Callable p_callback, float p_from, float p_to, float p_duration);
+ Ref<MethodTweener> tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration);
void append(Ref<Tweener> p_tweener);
bool custom_step(float p_delta);
@@ -258,7 +258,7 @@ public:
void start() override;
bool step(float &r_delta) override;
- MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration);
+ MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration);
MethodTweener();
protected:
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index e7769f9372..c7d1d7ef82 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -227,17 +227,17 @@ void CodeEdit::_notification(int p_what) {
end = font->get_string_size(line.substr(0, line.rfind(String::chr(0xFFFF))), font_size).x;
}
- Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent() + font_height * i + yofs);
+ Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent(font_size) + font_height * i + yofs);
round_ofs = round_ofs.round();
draw_string(font, round_ofs, line.replace(String::chr(0xFFFF), ""), HALIGN_LEFT, -1, font_size, font_color);
if (end > 0) {
// Draw an underline for the currently edited function parameter.
- const Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font_height + font_height * i + line_spacing);
+ const Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font_height + font_height * i + yofs);
draw_line(b, b + Vector2(end - begin, 0), font_color, 2);
// Draw a translucent text highlight as well.
const Rect2 highlight_rect = Rect2(
- hint_ofs + sb->get_offset() + Vector2(begin, 0),
+ b - Vector2(0, font_height),
Vector2(end - begin, font_height));
draw_rect(highlight_rect, font_color * Color(1, 1, 1, 0.2));
}
@@ -296,7 +296,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
mpos.x = get_size().x - mpos.x;
}
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int line = pos.y;
int col = pos.x;
@@ -321,7 +321,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
mpos.x = get_size().x - mpos.x;
}
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int line = pos.y;
int col = pos.x;
@@ -467,7 +467,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
/* MISC */
- if (k->is_action("ui_cancel", true)) {
+ if (!code_hint.is_empty() && k->is_action("ui_cancel", true)) {
set_code_hint("");
accept_event();
return;
@@ -1725,14 +1725,17 @@ bool CodeEdit::is_code_completion_enabled() const {
void CodeEdit::set_code_completion_prefixes(const TypedArray<String> &p_prefixes) {
code_completion_prefixes.clear();
for (int i = 0; i < p_prefixes.size(); i++) {
- code_completion_prefixes.insert(p_prefixes[i]);
+ const String prefix = p_prefixes[i];
+
+ ERR_CONTINUE_MSG(prefix.is_empty(), "Code completion prefix cannot be empty.");
+ code_completion_prefixes.insert(prefix[0]);
}
}
TypedArray<String> CodeEdit::get_code_completion_prefixes() const {
TypedArray<String> prefixes;
- for (Set<String>::Element *E = code_completion_prefixes.front(); E; E = E->next()) {
- prefixes.push_back(E->get());
+ for (const Set<char32_t>::Element *E = code_completion_prefixes.front(); E; E = E->next()) {
+ prefixes.push_back(String::chr(E->get()));
}
return prefixes;
}
@@ -1795,9 +1798,9 @@ void CodeEdit::request_code_completion(bool p_force) {
String line = get_line(get_caret_line());
int ofs = CLAMP(get_caret_column(), 0, line.length());
- if (ofs > 0 && (is_in_string(get_caret_line(), ofs) != -1 || _is_char(line[ofs - 1]) || code_completion_prefixes.has(String::chr(line[ofs - 1])))) {
+ if (ofs > 0 && (is_in_string(get_caret_line(), ofs) != -1 || _is_char(line[ofs - 1]) || code_completion_prefixes.has(line[ofs - 1]))) {
emit_signal(SNAME("request_code_completion"));
- } else if (ofs > 1 && line[ofs - 1] == ' ' && code_completion_prefixes.has(String::chr(line[ofs - 2]))) {
+ } else if (ofs > 1 && line[ofs - 1] == ' ' && code_completion_prefixes.has(line[ofs - 2])) {
emit_signal(SNAME("request_code_completion"));
}
}
@@ -1969,7 +1972,7 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
end_complex_operation();
cancel_code_completion();
- if (code_completion_prefixes.has(String::chr(last_completion_char))) {
+ if (code_completion_prefixes.has(last_completion_char)) {
request_code_completion();
}
}
@@ -2764,7 +2767,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
bool prev_is_word = false;
/* Cancel if we are at the close of a string. */
- if (in_string == -1 && first_quote_col == cofs - 1) {
+ if (caret_column > 0 && in_string == -1 && first_quote_col == cofs - 1) {
cancel_code_completion();
return;
/* In a string, therefore we are trying to complete the string text. */
@@ -2790,9 +2793,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
/* If all else fails, check for a prefix. */
/* Single space between caret and prefix is okay. */
bool prev_is_prefix = false;
- if (cofs > 0 && code_completion_prefixes.has(String::chr(line[cofs - 1]))) {
+ if (cofs > 0 && code_completion_prefixes.has(line[cofs - 1])) {
prev_is_prefix = true;
- } else if (cofs > 1 && line[cofs - 1] == ' ' && code_completion_prefixes.has(String::chr(line[cofs - 2]))) {
+ } else if (cofs > 1 && line[cofs - 1] == ' ' && code_completion_prefixes.has(line[cofs - 2])) {
prev_is_prefix = true;
}
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 740548d559..d8eccb7d32 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -214,7 +214,7 @@ private:
int code_completion_longest_line = 0;
Rect2i code_completion_rect;
- Set<String> code_completion_prefixes;
+ Set<char32_t> code_completion_prefixes;
List<ScriptCodeCompletionOption> code_completion_option_submitted;
List<ScriptCodeCompletionOption> code_completion_option_sources;
String code_completion_base;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 1afb0b8e9d..611035fff9 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -827,7 +827,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
real_t dist = center.distance_to(bev->get_position());
if (dist <= center.x) {
- real_t rad = Math::atan2(bev->get_position().y - center.y, bev->get_position().x - center.x);
+ real_t rad = bev->get_position().angle_to_point(center);
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
s = CLAMP(dist / center.x, 0, 1);
} else {
@@ -844,7 +844,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
real_t dist = center.distance_to(bev->get_position());
if (dist >= center.x * 0.84 && dist <= center.x) {
- real_t rad = Math::atan2(bev->get_position().y - center.y, bev->get_position().x - center.x);
+ real_t rad = bev->get_position().angle_to_point(center);
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
spinning = true;
} else {
@@ -889,12 +889,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
Vector2 center = c->get_size() / 2.0;
if (picker_type == SHAPE_VHS_CIRCLE) {
real_t dist = center.distance_to(mev->get_position());
- real_t rad = Math::atan2(mev->get_position().y - center.y, mev->get_position().x - center.x);
+ real_t rad = mev->get_position().angle_to_point(center);
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
s = CLAMP(dist / center.x, 0, 1);
} else {
if (spinning) {
- real_t rad = Math::atan2(mev->get_position().y - center.y, mev->get_position().x - center.x);
+ real_t rad = mev->get_position().angle_to_point(center);
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
} else {
real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
@@ -996,7 +996,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mev = p_event;
if (mev.is_valid()) {
Viewport *r = get_tree()->get_root();
- if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) {
+ if (!r->get_visible_rect().has_point(mev->get_global_position())) {
return;
}
@@ -1308,6 +1308,8 @@ void ColorPickerButton::_modal_closed() {
void ColorPickerButton::pressed() {
_update_picker();
+ Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
+
popup->set_as_minsize();
picker->_update_presets();
@@ -1319,13 +1321,13 @@ void ColorPickerButton::pressed() {
if (i > 1) {
cp_rect.position.y = get_screen_position().y - cp_rect.size.y;
} else {
- cp_rect.position.y = get_screen_position().y + get_size().height;
+ cp_rect.position.y = get_screen_position().y + size.height;
}
if (i & 1) {
cp_rect.position.x = get_screen_position().x;
} else {
- cp_rect.position.x = get_screen_position().x - MAX(0, (cp_rect.size.x - get_size().x));
+ cp_rect.position.x = get_screen_position().x - MAX(0, (cp_rect.size.x - size.x));
}
if (usable_rect.encloses(cp_rect)) {
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index c97434f69b..11941529cd 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -96,17 +96,18 @@ void Container::fit_child_in_rect(Control *p_child, const Rect2 &p_rect) {
ERR_FAIL_COND(!p_child);
ERR_FAIL_COND(p_child->get_parent() != this);
+ bool rtl = is_layout_rtl();
Size2 minsize = p_child->get_combined_minimum_size();
Rect2 r = p_rect;
if (!(p_child->get_h_size_flags() & SIZE_FILL)) {
r.size.x = minsize.width;
if (p_child->get_h_size_flags() & SIZE_SHRINK_END) {
- r.position.x += p_rect.size.width - minsize.width;
+ r.position.x += rtl ? 0 : (p_rect.size.width - minsize.width);
} else if (p_child->get_h_size_flags() & SIZE_SHRINK_CENTER) {
r.position.x += Math::floor((p_rect.size.x - minsize.width) / 2);
} else {
- r.position.x += 0;
+ r.position.x += rtl ? (p_rect.size.width - minsize.width) : 0;
}
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index cabae9feb2..d9c08ec272 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -356,16 +356,6 @@ void GraphEdit::_graph_node_raised(Node *p_gn) {
} else {
gn->raise();
}
- int first_not_comment = 0;
- for (int i = 0; i < get_child_count(); i++) {
- GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
- if (gn2 && !gn2->is_comment()) {
- first_not_comment = i;
- break;
- }
- }
-
- move_child(connections_layer, first_not_comment);
emit_signal(SNAME("node_selected"), p_gn);
}
@@ -707,7 +697,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
} else if (!just_disconnected) {
String from = connecting_from;
int from_slot = connecting_index;
- Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y);
+ Vector2 ofs = mb->get_position();
if (!connecting_out) {
emit_signal(SNAME("connection_from_empty"), from, from_slot, ofs);
@@ -1081,10 +1071,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (mm.is_valid() && box_selecting) {
box_selecting_to = mm->get_position();
- box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x),
- MIN(box_selecting_from.y, box_selecting_to.y),
- ABS(box_selecting_from.x - box_selecting_to.x),
- ABS(box_selecting_from.y - box_selecting_to.y));
+ box_selecting_rect = Rect2(box_selecting_from.min(box_selecting_to), (box_selecting_from - box_selecting_to).abs());
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -2113,7 +2100,7 @@ void GraphEdit::arrange_nodes() {
largest_node_size = 0.0f;
}
- emit_signal("begin_node_move");
+ emit_signal(SNAME("begin_node_move"));
for (const Set<StringName>::Element *E = selected_nodes.front(); E; E = E->next()) {
GraphNode *gn = Object::cast_to<GraphNode>(node_names[E->get()]);
gn->set_drag(true);
@@ -2126,7 +2113,7 @@ void GraphEdit::arrange_nodes() {
gn->set_position_offset(pos);
gn->set_drag(false);
}
- emit_signal("end_node_move");
+ emit_signal(SNAME("end_node_move"));
arranging_graph = false;
}
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 08c8c60d7a..ecf735d7f5 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -31,6 +31,9 @@
#include "graph_node.h"
#include "core/string/translation.h"
+#ifdef TOOLS_ENABLED
+#include "graph_edit.h"
+#endif
struct _MinSizeCache {
int min_size;
@@ -458,6 +461,27 @@ void GraphNode::_shape() {
title_buf->add_string(title, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
}
+#ifdef TOOLS_ENABLED
+void GraphNode::_edit_set_position(const Point2 &p_position) {
+ GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
+ if (graph) {
+ Point2 offset = (p_position + graph->get_scroll_ofs()) * graph->get_zoom();
+ set_position_offset(offset);
+ }
+ set_position(p_position);
+}
+
+void GraphNode::_validate_property(PropertyInfo &property) const {
+ Control::_validate_property(property);
+ GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
+ if (graph) {
+ if (property.name == "rect_position") {
+ property.usage |= PROPERTY_USAGE_READ_ONLY;
+ }
+ }
+}
+#endif
+
void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right) {
ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set slot with p_idx (%d) lesser than zero.", p_idx));
@@ -871,7 +895,7 @@ void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node.");
if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- Vector2 mpos = Vector2(mb->get_position().x, mb->get_position().y);
+ Vector2 mpos = mb->get_position();
if (close_rect.size != Size2() && close_rect.has_point(mpos)) {
//send focus to parent
get_parent_control()->grab_focus();
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index c7c7006bfc..2238cfdb56 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -98,6 +98,11 @@ private:
Overlay overlay = OVERLAY_DISABLED;
+#ifdef TOOLS_ENABLED
+ void _edit_set_position(const Point2 &p_position) override;
+ void _validate_property(PropertyInfo &property) const override;
+#endif
+
protected:
virtual void gui_input(const Ref<InputEvent> &p_ev) override;
void _notification(int p_what);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 5600816b2d..18cde25e55 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -92,8 +92,12 @@ void Label::_shape() {
const Ref<Font> &font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
ERR_FAIL_COND(font.is_null());
- TS->shaped_text_add_string(text_rid, (uppercase) ? xl_text.to_upper() : xl_text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
- TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, xl_text));
+ String text = (uppercase) ? xl_text.to_upper() : xl_text;
+ if (visible_chars >= 0) {
+ text = text.substr(0, visible_chars);
+ }
+ TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text));
dirty = false;
lines_dirty = true;
}
@@ -258,11 +262,18 @@ void Label::_notification(int p_what) {
return; // Nothing new.
}
xl_text = new_text;
+ if (percent_visible < 1) {
+ visible_chars = get_total_character_count() * percent_visible;
+ }
dirty = true;
update();
}
+ if (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED) {
+ update();
+ }
+
if (p_what == NOTIFICATION_DRAW) {
if (clip) {
RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
@@ -286,6 +297,7 @@ void Label::_notification(int p_what) {
int outline_size = get_theme_constant(SNAME("outline_size"));
int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
bool rtl = TS->shaped_text_get_direction(text_rid);
+ bool rtl_layout = is_layout_rtl();
style->draw(ci, Rect2(Point2(0, 0), get_size()));
@@ -342,24 +354,6 @@ void Label::_notification(int p_what) {
}
}
- int visible_glyphs = -1;
- int glyhps_drawn = 0;
- if (percent_visible < 1) {
- int total_glyphs = 0;
- for (int i = lines_skipped; i < last_line; i++) {
- const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
- const TextServer::Glyph *glyphs = visual.ptr();
- int gl_size = visual.size();
- for (int j = 0; j < gl_size; j++) {
- if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- total_glyphs++;
- }
- }
- }
-
- visible_glyphs = MIN(total_glyphs, visible_chars);
- }
-
Vector2 ofs;
ofs.y = style->get_offset().y + vbegin;
for (int i = lines_skipped; i < last_line; i++) {
@@ -375,13 +369,21 @@ void Label::_notification(int p_what) {
}
break;
case ALIGN_LEFT: {
- ofs.x = style->get_offset().x;
+ if (rtl_layout) {
+ ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width);
+ } else {
+ ofs.x = style->get_offset().x;
+ }
} break;
case ALIGN_CENTER: {
ofs.x = int(size.width - line_size.width) / 2;
} break;
case ALIGN_RIGHT: {
- ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width);
+ if (rtl_layout) {
+ ofs.x = style->get_offset().x;
+ } else {
+ ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width);
+ }
} break;
}
@@ -407,14 +409,6 @@ void Label::_notification(int p_what) {
// Draw main text.
for (int j = 0; j < gl_size; j++) {
for (int k = 0; k < glyphs[j].repeat; k++) {
- if (visible_glyphs != -1) {
- if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- if (glyhps_drawn >= visible_glyphs) {
- return;
- }
- }
- }
-
// Trim when necessary.
if (trim_data.trim_pos >= 0) {
if (rtl) {
@@ -431,7 +425,6 @@ void Label::_notification(int p_what) {
// Draw glyph outlines and shadow.
draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
offset.x += glyphs[j].advance;
- glyhps_drawn++;
}
}
// Draw LTR ellipsis string when necessary.
@@ -462,14 +455,6 @@ void Label::_notification(int p_what) {
// Draw main text.
for (int j = 0; j < gl_size; j++) {
for (int k = 0; k < glyphs[j].repeat; k++) {
- if (visible_glyphs != -1) {
- if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- if (glyhps_drawn >= visible_glyphs) {
- return;
- }
- }
- }
-
// Trim when necessary.
if (trim_data.trim_pos >= 0) {
if (rtl) {
@@ -486,7 +471,6 @@ void Label::_notification(int p_what) {
// Draw glyph outlines and shadow.
draw_glyph(glyphs[j], ci, font_color, ofs);
ofs.x += glyphs[j].advance;
- glyhps_drawn++;
}
}
// Draw LTR ellipsis string when necessary.
@@ -709,16 +693,16 @@ String Label::get_text() const {
}
void Label::set_visible_characters(int p_amount) {
- visible_chars = p_amount;
- if (get_total_character_count() > 0) {
- percent_visible = (float)p_amount / (float)get_total_character_count();
- } else {
- percent_visible = 1.0;
- }
- if (p_amount == -1) {
- lines_dirty = true;
+ if (visible_chars != p_amount) {
+ visible_chars = p_amount;
+ if (get_total_character_count() > 0) {
+ percent_visible = (float)p_amount / (float)get_total_character_count();
+ } else {
+ percent_visible = 1.0;
+ }
+ dirty = true;
+ update();
}
- update();
}
int Label::get_visible_characters() const {
@@ -726,15 +710,17 @@ int Label::get_visible_characters() const {
}
void Label::set_percent_visible(float p_percent) {
- if (p_percent < 0 || p_percent >= 1) {
- visible_chars = -1;
- percent_visible = 1;
- lines_dirty = true;
- } else {
- visible_chars = get_total_character_count() * p_percent;
- percent_visible = p_percent;
+ if (percent_visible != p_percent) {
+ if (p_percent < 0 || p_percent >= 1) {
+ visible_chars = -1;
+ percent_visible = 1;
+ } else {
+ visible_chars = get_total_character_count() * p_percent;
+ percent_visible = p_percent;
+ }
+ dirty = true;
+ update();
}
- update();
}
float Label::get_percent_visible() const {
@@ -889,7 +875,7 @@ void Label::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1", PROPERTY_USAGE_EDITOR), "set_visible_characters", "get_visible_characters");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE, "-1,999,1"), "set_max_lines_visible", "get_max_lines_visible");
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index d9acbeb828..09128770d5 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -260,24 +260,29 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
} else {
if (selecting_enabled) {
- if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ const int triple_click_timeout = 600;
+ const int triple_click_tolerance = 5;
+ const bool is_triple_click = !b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && b->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance;
+
+ if (is_triple_click && text.length()) {
// Triple-click select all.
selection.enabled = true;
selection.begin = 0;
selection.end = text.length();
selection.double_click = true;
- selection.last_dblclk = 0;
+ last_dblclk = 0;
caret_column = selection.begin;
} else if (b->is_double_click()) {
// Double-click select word.
+ last_dblclk = OS::get_singleton()->get_ticks_msec();
+ last_dblclk_pos = b->get_position();
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
- if (words[i].x < caret_column && words[i].y > caret_column) {
+ if ((words[i].x < caret_column && words[i].y > caret_column) || (i == words.size() - 1 && caret_column == words[i].y)) {
selection.enabled = true;
selection.begin = words[i].x;
selection.end = words[i].y;
selection.double_click = true;
- selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
caret_column = selection.end;
break;
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index e364a79c83..9f28c84f50 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -136,7 +136,6 @@ private:
bool creating = false;
bool double_click = false;
bool drag_attempt = false;
- uint64_t last_dblclk = 0;
} selection;
struct TextOperation {
@@ -153,6 +152,9 @@ private:
bool pressing_inside = false;
} clear_button_status;
+ uint64_t last_dblclk = 0;
+ Vector2 last_dblclk_pos;
+
bool caret_blink_enabled = false;
bool caret_force_displayed = false;
bool draw_caret = true;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 737ba84617..ceb2092e3a 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -87,15 +87,17 @@ void MenuButton::_popup_visibility_changed(bool p_visible) {
void MenuButton::pressed() {
emit_signal(SNAME("about_to_popup"));
- Size2 size = get_size();
+ Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
+ popup->set_size(Size2(size.width, 0));
Point2 gp = get_screen_position();
- gp.y += get_size().y;
-
+ gp.y += size.y;
+ if (is_layout_rtl()) {
+ gp.x += size.width - popup->get_size().width;
+ }
popup->set_position(gp);
+ popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size));
- popup->set_size(Size2(size.width, 0));
- popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size()));
popup->take_mouse_focus();
popup->popup();
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index d16e96dbec..2adeb2d947 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -115,7 +115,7 @@ void OptionButton::_selected(int p_which) {
}
void OptionButton::pressed() {
- Size2 size = get_size();
+ Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
popup->popup();
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index e9414598a2..be05fd5a60 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -194,7 +194,7 @@ Popup::~Popup() {
}
Size2 PopupPanel::_get_contents_minimum_size() const {
- Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name());
+ Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
Size2 ms;
@@ -217,7 +217,7 @@ Size2 PopupPanel::_get_contents_minimum_size() const {
}
void PopupPanel::_update_child_rects() {
- Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name());
+ Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
Vector2 cpos(p->get_offset());
Vector2 csize(get_size() - p->get_minimum_size());
@@ -244,9 +244,9 @@ void PopupPanel::_update_child_rects() {
void PopupPanel::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED) {
- panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name()));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
} else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) {
- panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name()));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
_update_child_rects();
} else if (p_what == NOTIFICATION_WM_SIZE_CHANGED) {
_update_child_rects();
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index 236d106af8..076fa132c0 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -90,6 +90,12 @@ void CharFXTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_glyph_index"), &CharFXTransform::get_glyph_index);
ClassDB::bind_method(D_METHOD("set_glyph_index", "glyph_index"), &CharFXTransform::set_glyph_index);
+ ClassDB::bind_method(D_METHOD("get_glyph_count"), &CharFXTransform::get_glyph_count);
+ ClassDB::bind_method(D_METHOD("set_glyph_count", "glyph_count"), &CharFXTransform::set_glyph_count);
+
+ ClassDB::bind_method(D_METHOD("get_glyph_flags"), &CharFXTransform::get_glyph_flags);
+ ClassDB::bind_method(D_METHOD("set_glyph_flags", "glyph_flags"), &CharFXTransform::set_glyph_flags);
+
ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font);
ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font);
@@ -101,5 +107,7 @@ void CharFXTransform::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "env"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_count"), "set_glyph_count", "get_glyph_count");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_flags"), "set_glyph_flags", "get_glyph_flags");
ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font");
}
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index f5506542bb..5681f9b193 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -50,6 +50,8 @@ public:
double elapsed_time = 0.0f;
Dictionary environment;
uint32_t glyph_index = 0;
+ uint16_t glyph_flags = 0;
+ uint8_t glyph_count = 0;
RID font;
CharFXTransform();
@@ -57,19 +59,31 @@ public:
Vector2i get_range() { return range; }
void set_range(const Vector2i &p_range) { range = p_range; }
+
double get_elapsed_time() { return elapsed_time; }
void set_elapsed_time(double p_elapsed_time) { elapsed_time = p_elapsed_time; }
+
bool is_visible() { return visibility; }
void set_visibility(bool p_visibility) { visibility = p_visibility; }
+
bool is_outline() { return outline; }
void set_outline(bool p_outline) { outline = p_outline; }
+
Point2 get_offset() { return offset; }
void set_offset(Point2 p_offset) { offset = p_offset; }
+
Color get_color() { return color; }
void set_color(Color p_color) { color = p_color; }
uint32_t get_glyph_index() const { return glyph_index; };
void set_glyph_index(uint32_t p_glyph_index) { glyph_index = p_glyph_index; };
+
+ uint16_t get_glyph_flags() const { return glyph_index; };
+ void set_glyph_flags(uint16_t p_glyph_flags) { glyph_flags = p_glyph_flags; };
+
+ uint8_t get_glyph_count() const { return glyph_count; };
+ void set_glyph_count(uint8_t p_glyph_count) { glyph_count = p_glyph_count; };
+
RID get_font() const { return font; };
void set_font(RID p_font) { font = p_font; };
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 562bac60c2..277026cc28 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -333,7 +333,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font>
} else {
frame->lines.write[i].offset.y = 0;
}
- frame->lines.write[i].offset += Vector2(offset.x, offset.y);
+ frame->lines.write[i].offset += offset;
float h = frame->lines[i].text_buf->get_size().y;
if (frame->min_size_over.y > 0) {
@@ -399,8 +399,9 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
// Shape current paragraph.
String text;
Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ int remaining_characters = visible_characters - l.char_offset;
for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
- if (visible_characters >= 0 && l.char_offset + l.char_count > visible_characters) {
+ if (visible_characters >= 0 && remaining_characters <= 0) {
break;
}
switch (it->type) {
@@ -427,7 +428,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
}
l.text_buf->add_string("\n", font, font_size, Dictionary(), "");
text += "\n";
- l.char_count += 1;
+ l.char_count++;
+ remaining_characters--;
} break;
case ITEM_TEXT: {
ItemText *t = (ItemText *)it;
@@ -442,9 +444,10 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
Dictionary font_ftr = _find_font_features(it);
String lang = _find_language(it);
String tx = t->text;
- if (visible_characters >= 0 && l.char_offset + l.char_count + tx.length() > visible_characters) {
- tx = tx.substr(0, l.char_offset + l.char_count + tx.length() - visible_characters);
+ if (visible_characters >= 0 && remaining_characters >= 0) {
+ tx = tx.substr(0, remaining_characters);
}
+ remaining_characters -= tx.length();
l.text_buf->add_string(tx, font, font_size, font_ftr, lang);
text += tx;
@@ -454,7 +457,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
ItemImage *img = (ItemImage *)it;
l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1);
text += String::chr(0xfffc);
- l.char_count += 1;
+ l.char_count++;
+ remaining_characters--;
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
@@ -483,6 +487,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
int cell_ch = (char_offset - (l.char_offset + l.char_count));
l.char_count += cell_ch;
t_char_count += cell_ch;
+ remaining_characters -= cell_ch;
table->columns.write[column].min_width = MAX(table->columns[column].min_width, ceil(frame->lines[i].text_buf->get_size().x));
table->columns.write[column].max_width = MAX(table->columns[column].max_width, ceil(frame->lines[i].text_buf->get_non_wraped_size().x));
@@ -573,7 +578,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
} else {
frame->lines.write[i].offset.y = 0;
}
- frame->lines.write[i].offset += Vector2(offset.x, offset.y);
+ frame->lines.write[i].offset += offset;
float h = frame->lines[i].text_buf->get_size().y;
if (frame->min_size_over.y > 0) {
@@ -847,6 +852,21 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
RID frid = glyphs[i].font_rid;
uint32_t gl = glyphs[i].index;
+ uint16_t gl_fl = glyphs[i].flags;
+ uint8_t gl_cn = glyphs[i].count;
+ bool cprev = false;
+ if (gl_cn == 0) { // Parts of the same cluster, always connected.
+ cprev = true;
+ }
+ if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
+ if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
+ cprev = true;
+ }
+ } else {
+ if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
+ cprev = true;
+ }
+ }
//Apply fx.
float faded_visibility = 1.0f;
@@ -875,6 +895,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
charfx->outline = true;
charfx->font = frid;
charfx->glyph_index = gl;
+ charfx->glyph_flags = gl_fl;
+ charfx->glyph_count = gl_cn;
charfx->offset = fx_offset;
charfx->color = font_color;
@@ -890,25 +912,34 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
- uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
- uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
- uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
- n_time = (n_time > 1.0) ? 1.0 : n_time;
- fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ if (!cprev) {
+ uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
+ uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
+ uint64_t max_rand = 2147483647;
+ double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
+ n_time = (n_time > 1.0) ? 1.0 : n_time;
+ item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ }
+ fx_offset += item_shake->prev_off;
} else if (item_fx->type == ITEM_WAVE) {
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
- double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
- fx_offset += Point2(0, 1) * value;
+ if (!cprev) {
+ double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_wave->amplitude / 10.0f);
+ item_wave->prev_off = Point2(0, 1) * value;
+ }
+ fx_offset += item_wave->prev_off;
} else if (item_fx->type == ITEM_TORNADO) {
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
- double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
- double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
- fx_offset += Point2(torn_x, torn_y);
+ if (!cprev) {
+ double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
+ double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
+ item_tornado->prev_off = Point2(torn_x, torn_y);
+ }
+ fx_offset += item_tornado->prev_off;
} else if (item_fx->type == ITEM_RAINBOW) {
ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
@@ -999,6 +1030,21 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
RID frid = glyphs[i].font_rid;
uint32_t gl = glyphs[i].index;
+ uint16_t gl_fl = glyphs[i].flags;
+ uint8_t gl_cn = glyphs[i].count;
+ bool cprev = false;
+ if (gl_cn == 0) { // Parts of the same grapheme cluster, always connected.
+ cprev = true;
+ }
+ if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
+ if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
+ cprev = true;
+ }
+ } else {
+ if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
+ cprev = true;
+ }
+ }
//Apply fx.
float faded_visibility = 1.0f;
@@ -1027,6 +1073,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
charfx->outline = false;
charfx->font = frid;
charfx->glyph_index = gl;
+ charfx->glyph_flags = gl_fl;
+ charfx->glyph_count = gl_cn;
charfx->offset = fx_offset;
charfx->color = font_color;
@@ -1042,25 +1090,34 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
- uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
- uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
- uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
- n_time = (n_time > 1.0) ? 1.0 : n_time;
- fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ if (!cprev) {
+ uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
+ uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
+ uint64_t max_rand = 2147483647;
+ double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
+ n_time = (n_time > 1.0) ? 1.0 : n_time;
+ item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ }
+ fx_offset += item_shake->prev_off;
} else if (item_fx->type == ITEM_WAVE) {
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
- double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
- fx_offset += Point2(0, 1) * value;
+ if (!cprev) {
+ double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
+ item_wave->prev_off = Point2(0, 1) * value;
+ }
+ fx_offset += item_wave->prev_off;
} else if (item_fx->type == ITEM_TORNADO) {
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
- double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
- double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
- fx_offset += Point2(torn_x, torn_y);
+ if (!cprev) {
+ double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
+ double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
+ item_tornado->prev_off = Point2(torn_x, torn_y);
+ }
+ fx_offset += item_tornado->prev_off;
} else if (item_fx->type == ITEM_RAINBOW) {
ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
@@ -1374,8 +1431,8 @@ void RichTextLabel::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
- if (bbcode != "") {
- set_bbcode(bbcode);
+ if (text != "") {
+ set_text(text);
}
main->first_invalid_line = 0; //invalidate ALL
@@ -2321,8 +2378,7 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
item->size.width = p_image->get_width() * p_height / p_image->get_height();
} else {
// keep original width and height
- item->size.height = p_image->get_height();
- item->size.width = p_image->get_width();
+ item->size = p_image->get_size();
}
}
@@ -2767,10 +2823,10 @@ bool RichTextLabel::is_scroll_following() const {
Error RichTextLabel::parse_bbcode(const String &p_bbcode) {
clear();
- return append_bbcode(p_bbcode);
+ return append_text(p_bbcode);
}
-Error RichTextLabel::append_bbcode(const String &p_bbcode) {
+Error RichTextLabel::append_text(const String &p_bbcode) {
int pos = 0;
List<String> tag_stack;
@@ -3824,8 +3880,8 @@ int RichTextLabel::get_selection_to() const {
return selection.to_frame->lines[selection.to_line].char_offset + selection.to_char - 1;
}
-void RichTextLabel::set_bbcode(const String &p_bbcode) {
- bbcode = p_bbcode;
+void RichTextLabel::set_text(const String &p_bbcode) {
+ text = p_bbcode;
if (is_inside_tree() && use_bbcode) {
parse_bbcode(p_bbcode);
} else { // raw text
@@ -3834,8 +3890,8 @@ void RichTextLabel::set_bbcode(const String &p_bbcode) {
}
}
-String RichTextLabel::get_bbcode() const {
- return bbcode;
+String RichTextLabel::get_text() const {
+ return text;
}
void RichTextLabel::set_use_bbcode(bool p_enable) {
@@ -3843,19 +3899,24 @@ void RichTextLabel::set_use_bbcode(bool p_enable) {
return;
}
use_bbcode = p_enable;
- set_bbcode(bbcode);
notify_property_list_changed();
+ set_text(text);
}
bool RichTextLabel::is_using_bbcode() const {
return use_bbcode;
}
-String RichTextLabel::get_text() {
+String RichTextLabel::get_parsed_text() const {
String text = "";
Item *it = main;
while (it) {
- if (it->type == ITEM_TEXT) {
+ if (it->type == ITEM_DROPCAP) {
+ const ItemDropcap *dc = (ItemDropcap *)it;
+ if (dc != nullptr) {
+ text += dc->text;
+ }
+ } else if (it->type == ITEM_TEXT) {
ItemText *t = static_cast<ItemText *>(it);
text += t->text;
} else if (it->type == ITEM_NEWLINE) {
@@ -3870,11 +3931,6 @@ String RichTextLabel::get_text() {
return text;
}
-void RichTextLabel::set_text(const String &p_string) {
- clear();
- add_text(p_string);
-}
-
void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction) {
ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
if (text_direction != p_text_direction) {
@@ -3931,7 +3987,6 @@ void RichTextLabel::set_percent_visible(float p_percent) {
if (p_percent < 0 || p_percent >= 1) {
visible_characters = -1;
percent_visible = 1;
-
} else {
visible_characters = get_total_character_count() * p_percent;
percent_visible = p_percent;
@@ -3948,8 +4003,8 @@ float RichTextLabel::get_percent_visible() const {
void RichTextLabel::set_effects(Array p_effects) {
custom_effects = p_effects;
- if ((bbcode != "") && use_bbcode) {
- parse_bbcode(bbcode);
+ if ((text != "") && use_bbcode) {
+ parse_bbcode(text);
}
}
@@ -3963,8 +4018,8 @@ void RichTextLabel::install_effect(const Variant effect) {
if (rteffect.is_valid()) {
custom_effects.push_back(effect);
- if ((bbcode != "") && use_bbcode) {
- parse_bbcode(bbcode);
+ if ((text != "") && use_bbcode) {
+ parse_bbcode(text);
}
}
}
@@ -3977,14 +4032,20 @@ int RichTextLabel::get_content_height() const {
return total_height;
}
-void RichTextLabel::_validate_property(PropertyInfo &property) const {
- if (!use_bbcode && property.name == "bbcode_text") {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+#ifndef DISABLE_DEPRECATED
+// People will be very angry, if their texts get erased, because of #39148. (3.x -> 4.0)
+// Altough some people may not used bbcode_text, so we only overwrite, if bbcode_text is not empty
+bool RichTextLabel::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "bbcode_text" && !((String)p_value).is_empty()) {
+ set_text(p_value);
+ return true;
}
+ return false;
}
+#endif
void RichTextLabel::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
+ ClassDB::bind_method(D_METHOD("get_parsed_text"), &RichTextLabel::get_parsed_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGN_CENTER));
@@ -4062,10 +4123,9 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_selected_text"), &RichTextLabel::get_selected_text);
ClassDB::bind_method(D_METHOD("parse_bbcode", "bbcode"), &RichTextLabel::parse_bbcode);
- ClassDB::bind_method(D_METHOD("append_bbcode", "bbcode"), &RichTextLabel::append_bbcode);
+ ClassDB::bind_method(D_METHOD("append_text", "bbcode"), &RichTextLabel::append_text);
- ClassDB::bind_method(D_METHOD("set_bbcode", "text"), &RichTextLabel::set_bbcode);
- ClassDB::bind_method(D_METHOD("get_bbcode"), &RichTextLabel::get_bbcode);
+ ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
ClassDB::bind_method(D_METHOD("set_visible_characters", "amount"), &RichTextLabel::set_visible_characters);
ClassDB::bind_method(D_METHOD("get_visible_characters"), &RichTextLabel::get_visible_characters);
@@ -4092,16 +4152,13 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_effects"), &RichTextLabel::get_effects);
ClassDB::bind_method(D_METHOD("install_effect", "effect"), &RichTextLabel::install_effect);
- ADD_GROUP("BBCode", "bbcode_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "bbcode_text", PROPERTY_HINT_MULTILINE_TEXT), "set_bbcode", "get_bbcode");
-
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fit_content_height"), "set_fit_content_height", "is_fit_content_height_enabled");
@@ -4163,16 +4220,20 @@ void RichTextLabel::_bind_methods() {
}
void RichTextLabel::set_visible_characters(int p_visible) {
- visible_characters = p_visible;
- if (p_visible == -1) {
- percent_visible = 1;
- } else {
- int total_char_count = get_total_character_count();
- if (total_char_count > 0) {
- percent_visible = (float)p_visible / (float)total_char_count;
+ if (visible_characters != p_visible) {
+ visible_characters = p_visible;
+ if (p_visible == -1) {
+ percent_visible = 1;
+ } else {
+ int total_char_count = get_total_character_count();
+ if (total_char_count > 0) {
+ percent_visible = (float)p_visible / (float)total_char_count;
+ }
}
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
}
- update();
}
int RichTextLabel::get_visible_characters() const {
@@ -4180,9 +4241,19 @@ int RichTextLabel::get_visible_characters() const {
}
int RichTextLabel::get_total_character_count() const {
+ // Note: Do not use line buffer "char_count", it includes only visible characters.
int tc = 0;
- for (int i = 0; i < current_frame->lines.size(); i++) {
- tc += current_frame->lines[i].char_count;
+ Item *it = main;
+ while (it) {
+ if (it->type == ITEM_TEXT) {
+ ItemText *t = static_cast<ItemText *>(it);
+ tc += t->text.length();
+ } else if (it->type == ITEM_NEWLINE) {
+ tc++;
+ } else if (it->type == ITEM_IMAGE) {
+ tc++;
+ }
+ it = _get_next_item(it, true);
}
return tc;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index f25a8bf193..94f02a3989 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -85,7 +85,6 @@ public:
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
private:
struct Item;
@@ -268,6 +267,7 @@ private:
float rate = 0.0f;
uint64_t _current_rng = 0;
uint64_t _previous_rng = 0;
+ Vector2 prev_off;
ItemShake() { type = ITEM_SHAKE; }
@@ -290,6 +290,7 @@ private:
struct ItemWave : public ItemFX {
float frequency = 1.0f;
float amplitude = 1.0f;
+ Vector2 prev_off;
ItemWave() { type = ITEM_WAVE; }
};
@@ -297,6 +298,7 @@ private:
struct ItemTornado : public ItemFX {
float radius = 1.0f;
float frequency = 1.0f;
+ Vector2 prev_off;
ItemTornado() { type = ITEM_TORNADO; }
};
@@ -452,16 +454,19 @@ private:
virtual Dictionary parse_expressions_for_values(Vector<String> p_expressions);
void _draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item *it_from, Item *it_to, int start, int end, int fbg_flag);
-
+#ifndef DISABLE_DEPRECATED
+ // Kept for compatibility from 3.x to 4.0.
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif
bool use_bbcode = false;
- String bbcode;
+ String text;
int fixed_width = -1;
bool fit_content_height = false;
public:
- String get_text();
+ String get_parsed_text() const;
void add_text(const String &p_text);
void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlign p_align = INLINE_ALIGN_CENTER);
void add_newline();
@@ -548,15 +553,13 @@ public:
void selection_copy();
Error parse_bbcode(const String &p_bbcode);
- Error append_bbcode(const String &p_bbcode);
+ Error append_text(const String &p_bbcode);
void set_use_bbcode(bool p_enable);
bool is_using_bbcode() const;
- void set_bbcode(const String &p_bbcode);
- String get_bbcode() const;
-
- void set_text(const String &p_string);
+ void set_text(const String &p_bbcode);
+ String get_text() const;
void set_text_direction(TextDirection p_text_direction);
TextDirection get_text_direction() const;
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 4edf373fbf..4a3a6837d5 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -560,7 +560,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) {
if (mm.is_valid()) {
if (drag_node_touching && !drag_node_touching_deaccel) {
- Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
+ Vector2 motion = mm->get_relative();
drag_node_accum -= motion;
Vector2 diff = drag_node_from + drag_node_accum;
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 0c051f61e2..0c0ec39c7f 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -167,7 +167,7 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mm.is_valid()) {
if (drag_touching && !drag_touching_deaccel) {
- Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
+ Vector2 motion = mm->get_relative();
drag_accum -= motion;
if (beyond_deadzone || (scroll_h && Math::abs(drag_accum.x) > deadzone) || (scroll_v && Math::abs(drag_accum.y) > deadzone)) {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 1074d0d8a0..0aec017649 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -68,6 +68,15 @@ void SpinBox::_text_submitted(const String &p_string) {
_value_changed(0);
}
+void SpinBox::_text_changed(const String &p_string) {
+ int cursor_pos = line_edit->get_caret_column();
+
+ _text_submitted(p_string);
+
+ // Line edit 'set_text' method resets the cursor position so we need to undo that.
+ line_edit->set_caret_column(cursor_pos);
+}
+
LineEdit *SpinBox::get_line_edit() {
return line_edit;
}
@@ -244,6 +253,24 @@ String SpinBox::get_prefix() const {
return prefix;
}
+void SpinBox::set_update_on_text_changed(bool p_update) {
+ if (update_on_text_changed == p_update) {
+ return;
+ }
+
+ update_on_text_changed = p_update;
+
+ if (p_update) {
+ line_edit->connect("text_changed", callable_mp(this, &SpinBox::_text_changed), Vector<Variant>(), CONNECT_DEFERRED);
+ } else {
+ line_edit->disconnect("text_changed", callable_mp(this, &SpinBox::_text_changed));
+ }
+}
+
+bool SpinBox::get_update_on_text_changed() const {
+ return update_on_text_changed;
+}
+
void SpinBox::set_editable(bool p_editable) {
line_edit->set_editable(p_editable);
}
@@ -267,11 +294,14 @@ void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_prefix"), &SpinBox::get_prefix);
ClassDB::bind_method(D_METHOD("set_editable", "editable"), &SpinBox::set_editable);
ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable);
+ ClassDB::bind_method(D_METHOD("set_update_on_text_changed"), &SpinBox::set_update_on_text_changed);
+ ClassDB::bind_method(D_METHOD("get_update_on_text_changed"), &SpinBox::get_update_on_text_changed);
ClassDB::bind_method(D_METHOD("apply"), &SpinBox::apply);
ClassDB::bind_method(D_METHOD("get_line_edit"), &SpinBox::get_line_edit);
ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_on_text_changed"), "set_update_on_text_changed", "get_update_on_text_changed");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
}
@@ -284,7 +314,6 @@ SpinBox::SpinBox() {
line_edit->set_mouse_filter(MOUSE_FILTER_PASS);
line_edit->set_align(LineEdit::ALIGN_LEFT);
- //connect("value_changed",this,"_value_changed");
line_edit->connect("text_submitted", callable_mp(this, &SpinBox::_text_submitted), Vector<Variant>(), CONNECT_DEFERRED);
line_edit->connect("focus_exited", callable_mp(this, &SpinBox::_line_edit_focus_exit), Vector<Variant>(), CONNECT_DEFERRED);
line_edit->connect("gui_input", callable_mp(this, &SpinBox::_line_edit_input));
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 9ec3885f1f..9828b894da 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -40,6 +40,7 @@ class SpinBox : public Range {
LineEdit *line_edit;
int last_w = 0;
+ bool update_on_text_changed = false;
Timer *range_click_timer;
void _range_click_timeout();
@@ -47,6 +48,8 @@ class SpinBox : public Range {
void _text_submitted(const String &p_string);
virtual void _value_changed(double) override;
+ void _text_changed(const String &p_string);
+
String prefix;
String suffix;
@@ -88,6 +91,9 @@ public:
void set_prefix(const String &p_prefix);
String get_prefix() const;
+ void set_update_on_text_changed(bool p_update);
+ bool get_update_on_text_changed() const;
+
void apply();
SpinBox();
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 137ce7e96f..c8a0501d8a 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -79,7 +79,7 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
Popup *popup = get_popup();
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- Point2 pos(mb->get_position().x, mb->get_position().y);
+ Point2 pos = mb->get_position();
Size2 size = get_size();
// Click must be on tabs in the tab header area.
@@ -190,7 +190,7 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- Point2 pos(mm->get_position().x, mm->get_position().y);
+ Point2 pos = mm->get_position();
Size2 size = get_size();
// Mouse must be on tabs in the tab header area.
@@ -538,7 +538,6 @@ void TabContainer::_notification(int p_what) {
void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) {
Control *control = get_tab_control(p_index);
RID canvas = get_canvas_item();
- Ref<Font> font = get_theme_font(SNAME("font"));
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
int icon_text_distance = get_theme_constant(SNAME("icon_separation"));
@@ -1134,7 +1133,6 @@ Size2 TabContainer::get_minimum_size() const {
Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- Ref<Font> font = get_theme_font(SNAME("font"));
if (tabs_visible) {
ms.y += MAX(MAX(tab_unselected->get_minimum_size().y, tab_selected->get_minimum_size().y), tab_disabled->get_minimum_size().y);
@@ -1212,6 +1210,8 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon);
ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled);
ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled);
+ ClassDB::bind_method(D_METHOD("set_tab_hidden", "tab_idx", "hidden"), &TabContainer::set_tab_hidden);
+ ClassDB::bind_method(D_METHOD("get_tab_hidden", "tab_idx"), &TabContainer::get_tab_hidden);
ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point);
ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup);
ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup);
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 3ca2d1c1e9..ef34bec347 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -98,29 +98,45 @@ void Tabs::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
Point2 pos = mm->get_position();
- highlight_arrow = -1;
if (buttons_visible) {
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
if (is_layout_rtl()) {
if (pos.x < decr->get_width()) {
- highlight_arrow = 1;
+ if (highlight_arrow != 1) {
+ highlight_arrow = 1;
+ update();
+ }
} else if (pos.x < incr->get_width() + decr->get_width()) {
- highlight_arrow = 0;
+ if (highlight_arrow != 0) {
+ highlight_arrow = 0;
+ update();
+ }
+ } else if (highlight_arrow != -1) {
+ highlight_arrow = -1;
+ update();
}
} else {
int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
if (pos.x > limit_minus_buttons + decr->get_width()) {
- highlight_arrow = 1;
+ if (highlight_arrow != 1) {
+ highlight_arrow = 1;
+ update();
+ }
} else if (pos.x > limit_minus_buttons) {
- highlight_arrow = 0;
+ if (highlight_arrow != 0) {
+ highlight_arrow = 0;
+ update();
+ }
+ } else if (highlight_arrow != -1) {
+ highlight_arrow = -1;
+ update();
}
}
}
_update_hover();
- update();
return;
}
@@ -167,7 +183,7 @@ void Tabs::gui_input(const Ref<InputEvent> &p_event) {
if (mb->is_pressed() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == MOUSE_BUTTON_RIGHT))) {
// clicks
- Point2 pos(mb->get_position().x, mb->get_position().y);
+ Point2 pos = mb->get_position();
if (buttons_visible) {
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
@@ -241,6 +257,7 @@ void Tabs::_shape(int p_tab) {
tabs.write[p_tab].xl_text = atr(tabs[p_tab].text);
tabs.write[p_tab].text_buf->clear();
+ tabs.write[p_tab].text_buf->set_width(-1);
if (tabs[p_tab].text_direction == Control::TEXT_DIRECTION_INHERITED) {
tabs.write[p_tab].text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
} else {
@@ -529,7 +546,6 @@ bool Tabs::get_offset_buttons_visible() const {
void Tabs::set_tab_title(int p_tab, const String &p_title) {
ERR_FAIL_INDEX(p_tab, tabs.size());
tabs.write[p_tab].text = p_title;
- tabs.write[p_tab].xl_text = atr(p_title);
_shape(p_tab);
update();
minimum_size_changed();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 06dfc31621..5b13e1da0b 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1444,7 +1444,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_reset_caret_blink_timer();
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int row = pos.y;
int col = pos.x;
@@ -1547,7 +1547,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
_reset_caret_blink_timer();
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int row = pos.y;
int col = pos.x;
@@ -3689,7 +3689,7 @@ void TextEdit::select_word_under_caret() {
int end = 0;
const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
for (int i = 0; i < words.size(); i++) {
- if (words[i].x <= caret.column && words[i].y >= caret.column) {
+ if ((words[i].x < caret.column && words[i].y > caret.column) || (i == words.size() - 1 && caret.column == words[i].y)) {
begin = words[i].x;
end = words[i].y;
break;
@@ -5385,7 +5385,7 @@ void TextEdit::_update_selection_mode_pointer() {
dragging_selection = true;
Point2 mp = get_local_mouse_pos();
- Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y));
+ Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
@@ -5402,7 +5402,7 @@ void TextEdit::_update_selection_mode_word() {
dragging_selection = true;
Point2 mp = get_local_mouse_pos();
- Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y));
+ Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
@@ -5411,7 +5411,7 @@ void TextEdit::_update_selection_mode_word() {
int end = beg;
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
for (int i = 0; i < words.size(); i++) {
- if (words[i].x < caret_pos && words[i].y > caret_pos) {
+ if ((words[i].x < caret_pos && words[i].y > caret_pos) || (i == words.size() - 1 && caret_pos == words[i].y)) {
beg = words[i].x;
end = words[i].y;
break;
@@ -5450,7 +5450,7 @@ void TextEdit::_update_selection_mode_line() {
dragging_selection = true;
Point2 mp = get_local_mouse_pos();
- Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y));
+ Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
@@ -5765,7 +5765,7 @@ void TextEdit::_update_minimap_hover() {
return;
}
- const int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y));
+ const int row = get_minimap_line_at_pos(mp);
const bool new_hovering_minimap = row >= get_first_visible_line() && row <= get_last_full_visible_line();
if (new_hovering_minimap != hovering_minimap) {
@@ -5786,7 +5786,7 @@ void TextEdit::_update_minimap_click() {
minimap_clicked = true;
dragging_minimap = true;
- int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y));
+ int row = get_minimap_line_at_pos(mp);
if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) {
minimap_scroll_ratio = v_scroll->get_as_ratio();
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 286f01ee33..35a098c6fd 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -471,7 +471,7 @@ void TextureProgressBar::_notification(int p_what) {
Vector<Point2> uvs;
Vector<Point2> points;
uvs.push_back(get_relative_center());
- points.push_back(progress_offset + Point2(s.x * get_relative_center().x, s.y * get_relative_center().y));
+ points.push_back(progress_offset + s * get_relative_center());
for (int i = 0; i < pts.size(); i++) {
Point2 uv = unit_val_to_uv(pts[i]);
if (uvs.find(uv) >= 0) {
@@ -493,8 +493,7 @@ void TextureProgressBar::_notification(int p_what) {
p = progress->get_size();
}
- p.x *= get_relative_center().x;
- p.y *= get_relative_center().y;
+ p *= get_relative_center();
p = p.floor();
draw_line(p - Point2(8, 0), p + Point2(8, 0), Color(0.9, 0.5, 0.5), 2);
draw_line(p - Point2(0, 8), p + Point2(0, 8), Color(0.9, 0.5, 0.5), 2);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index c4dfbc0d4e..7d7596635c 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -144,6 +144,7 @@ void TreeItem::_change_tree(Tree *p_tree) {
/* cell mode */
void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
ERR_FAIL_INDEX(p_column, cells.size());
+
Cell &c = cells.write[p_column];
c.mode = p_mode;
c.min = 0;
@@ -155,6 +156,8 @@ void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
c.text = "";
c.dirty = true;
c.icon_max_w = 0;
+ c.cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -166,19 +169,26 @@ TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const {
/* check mode */
void TreeItem::set_checked(int p_column, bool p_checked) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].checked = p_checked;
cells.write[p_column].indeterminate = false;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
void TreeItem::set_indeterminate(int p_column, bool p_indeterminate) {
ERR_FAIL_INDEX(p_column, cells.size());
+
// Prevent uncheck if indeterminate set to false twice
if (p_indeterminate == cells[p_column].indeterminate) {
return;
}
+
cells.write[p_column].indeterminate = p_indeterminate;
cells.write[p_column].checked = false;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -211,6 +221,9 @@ void TreeItem::set_text(int p_column, String p_text) {
}
cells.write[p_column].step = 0;
}
+
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -227,6 +240,7 @@ void TreeItem::set_text_direction(int p_column, Control::TextDirection p_text_di
cells.write[p_column].dirty = true;
_changed_notify(p_column);
}
+ cells.write[p_column].cached_minimum_size_dirty = true;
}
Control::TextDirection TreeItem::get_text_direction(int p_column) const {
@@ -236,8 +250,11 @@ Control::TextDirection TreeItem::get_text_direction(int p_column) const {
void TreeItem::clear_opentype_features(int p_column) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].opentype_features.clear();
cells.write[p_column].dirty = true;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -247,6 +264,8 @@ void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_va
if (!cells[p_column].opentype_features.has(tag) || (int)cells[p_column].opentype_features[tag] != p_value) {
cells.write[p_column].opentype_features[tag] = p_value;
cells.write[p_column].dirty = true;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
}
@@ -262,9 +281,12 @@ int TreeItem::get_opentype_feature(int p_column, const String &p_name) const {
void TreeItem::set_structured_text_bidi_override(int p_column, Control::StructuredTextParser p_parser) {
ERR_FAIL_INDEX(p_column, cells.size());
+
if (cells[p_column].st_parser != p_parser) {
cells.write[p_column].st_parser = p_parser;
cells.write[p_column].dirty = true;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
}
@@ -276,8 +298,11 @@ Control::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_
void TreeItem::set_structured_text_bidi_override_options(int p_column, Array p_args) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].st_args = p_args;
cells.write[p_column].dirty = true;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -288,9 +313,12 @@ Array TreeItem::get_structured_text_bidi_override_options(int p_column) const {
void TreeItem::set_language(int p_column, const String &p_language) {
ERR_FAIL_INDEX(p_column, cells.size());
+
if (cells[p_column].language != p_language) {
cells.write[p_column].language = p_language;
cells.write[p_column].dirty = true;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
}
@@ -302,7 +330,9 @@ String TreeItem::get_language(int p_column) const {
void TreeItem::set_suffix(int p_column, String p_suffix) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].suffix = p_suffix;
+ cells.write[p_column].cached_minimum_size_dirty = true;
_changed_notify(p_column);
}
@@ -314,7 +344,10 @@ String TreeItem::get_suffix(int p_column) const {
void TreeItem::set_icon(int p_column, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].icon = p_icon;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -325,7 +358,10 @@ Ref<Texture2D> TreeItem::get_icon(int p_column) const {
void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].icon_region = p_icon_region;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -347,7 +383,10 @@ Color TreeItem::get_icon_modulate(int p_column) const {
void TreeItem::set_icon_max_width(int p_column, int p_max) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].icon_max_w = p_max;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -460,6 +499,10 @@ void TreeItem::uncollapse_tree() {
void TreeItem::set_custom_minimum_height(int p_height) {
custom_min_height = p_height;
+
+ for (Cell &c : cells)
+ c.cached_minimum_size_dirty = true;
+
_changed_notify();
}
@@ -784,6 +827,8 @@ void TreeItem::add_button(int p_column, const Ref<Texture2D> &p_button, int p_id
button.disabled = p_disabled;
button.tooltip = p_tooltip;
cells.write[p_column].buttons.push_back(button);
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -827,6 +872,8 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
cells.write[p_column].buttons.write[p_idx].texture = p_button;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -842,6 +889,8 @@ void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
cells.write[p_column].buttons.write[p_idx].disabled = p_disabled;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -854,7 +903,10 @@ bool TreeItem::is_button_disabled(int p_column, int p_idx) const {
void TreeItem::set_editable(int p_column, bool p_editable) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].editable = p_editable;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -887,7 +939,9 @@ void TreeItem::clear_custom_color(int p_column) {
void TreeItem::set_custom_font(int p_column, const Ref<Font> &p_font) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].custom_font = p_font;
+ cells.write[p_column].cached_minimum_size_dirty = true;
}
Ref<Font> TreeItem::get_custom_font(int p_column) const {
@@ -897,7 +951,9 @@ Ref<Font> TreeItem::get_custom_font(int p_column) const {
void TreeItem::set_custom_font_size(int p_column, int p_font_size) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].custom_font_size = p_font_size;
+ cells.write[p_column].cached_minimum_size_dirty = true;
}
int TreeItem::get_custom_font_size(int p_column) const {
@@ -940,7 +996,9 @@ Color TreeItem::get_custom_bg_color(int p_column) const {
void TreeItem::set_custom_as_button(int p_column, bool p_button) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].custom_button = p_button;
+ cells.write[p_column].cached_minimum_size_dirty = true;
}
bool TreeItem::is_custom_set_as_button(int p_column) const {
@@ -950,7 +1008,10 @@ bool TreeItem::is_custom_set_as_button(int p_column) const {
void TreeItem::set_text_align(int p_column, TextAlign p_align) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].text_align = p_align;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -961,7 +1022,10 @@ TreeItem::TextAlign TreeItem::get_text_align(int p_column) const {
void TreeItem::set_expand_right(int p_column, bool p_enable) {
ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].expand_right = p_enable;
+ cells.write[p_column].cached_minimum_size_dirty = true;
+
_changed_notify(p_column);
}
@@ -972,6 +1036,10 @@ bool TreeItem::get_expand_right(int p_column) const {
void TreeItem::set_disable_folding(bool p_disable) {
disable_folding = p_disable;
+
+ for (Cell &c : cells)
+ c.cached_minimum_size_dirty = true;
+
_changed_notify(0);
}
@@ -984,49 +1052,52 @@ Size2 TreeItem::get_minimum_size(int p_column) {
Tree *tree = get_tree();
ERR_FAIL_COND_V(!tree, Size2());
- Size2 size;
+ const TreeItem::Cell &cell = cells[p_column];
- // Default offset?
- //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin;
+ if (cell.cached_minimum_size_dirty) {
+ Size2 size;
- // Text.
- const TreeItem::Cell &cell = cells[p_column];
- if (!cell.text.is_empty()) {
- if (cell.dirty) {
- tree->update_item_cell(this, p_column);
+ // Text.
+ if (!cell.text.is_empty()) {
+ if (cell.dirty) {
+ tree->update_item_cell(this, p_column);
+ }
+ Size2 text_size = cell.text_buf->get_size();
+ size.width += text_size.width;
+ size.height = MAX(size.height, text_size.height);
}
- Size2 text_size = cell.text_buf->get_size();
- size.width += text_size.width;
- size.height = MAX(size.height, text_size.height);
- }
- // Icon.
- if (cell.mode == CELL_MODE_CHECK) {
- size.width += tree->cache.checked->get_width() + tree->cache.hseparation;
- }
- if (cell.icon.is_valid()) {
- Size2i icon_size = cell.get_icon_size();
- if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) {
- icon_size.width = cell.icon_max_w;
+ // Icon.
+ if (cell.mode == CELL_MODE_CHECK) {
+ size.width += tree->cache.checked->get_width() + tree->cache.hseparation;
+ }
+ if (cell.icon.is_valid()) {
+ Size2i icon_size = cell.get_icon_size();
+ if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) {
+ icon_size.width = cell.icon_max_w;
+ }
+ size.width += icon_size.width + tree->cache.hseparation;
+ size.height = MAX(size.height, icon_size.height);
}
- size.width += icon_size.width + tree->cache.hseparation;
- size.height = MAX(size.height, icon_size.height);
- }
- // Buttons.
- for (int i = 0; i < cell.buttons.size(); i++) {
- Ref<Texture2D> texture = cell.buttons[i].texture;
- if (texture.is_valid()) {
- Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size();
- size.width += button_size.width;
- size.height = MAX(size.height, button_size.height);
+ // Buttons.
+ for (int i = 0; i < cell.buttons.size(); i++) {
+ Ref<Texture2D> texture = cell.buttons[i].texture;
+ if (texture.is_valid()) {
+ Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size();
+ size.width += button_size.width;
+ size.height = MAX(size.height, button_size.height);
+ }
}
- }
- if (cell.buttons.size() >= 2) {
- size.width += (cell.buttons.size() - 1) * tree->cache.button_margin;
+ if (cell.buttons.size() >= 2) {
+ size.width += (cell.buttons.size() - 1) * tree->cache.button_margin;
+ }
+
+ cells.write[p_column].cached_minimum_size = size;
+ cells.write[p_column].cached_minimum_size_dirty = false;
}
- return size;
+ return cell.cached_minimum_size;
}
Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -1678,7 +1749,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
if ((select_mode == SELECT_ROW && selected_item == p_item) || p_item->cells[i].selected || !p_item->has_meta("__focus_rect")) {
- Rect2i r(cell_rect.position, cell_rect.size);
+ Rect2i r = cell_rect;
p_item->set_meta("__focus_rect", Rect2(r.position, r.size));
@@ -1934,7 +2005,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
arrow = cache.arrow;
}
- Point2 apos = p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset;
+ Point2 apos = p_pos + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset + p_draw_ofs;
+ apos.x += cache.item_margin - arrow->get_width();
if (rtl) {
apos.x = get_size().width - apos.x - arrow->get_width();
@@ -3966,10 +4038,12 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
int Tree::get_column_minimum_width(int p_column) const {
ERR_FAIL_INDEX_V(p_column, columns.size(), -1);
+ // Use the custom minimum width.
int min_width = columns[p_column].custom_min_width;
+ // Check if the visible title of the column is wider.
if (show_column_titles) {
- min_width = MAX(cache.font->get_string_size(columns[p_column].title).width, min_width);
+ min_width = MAX(cache.font->get_string_size(columns[p_column].title).width + cache.bg->get_margin(SIDE_LEFT) + cache.bg->get_margin(SIDE_RIGHT), min_width);
}
if (!columns[p_column].clip_content) {
@@ -3994,7 +4068,11 @@ int Tree::get_column_minimum_width(int p_column) const {
Size2 item_size = item->get_minimum_size(p_column);
if (p_column == 0) {
item_size.width += cache.item_margin * depth;
+ } else {
+ item_size.width += cache.hseparation;
}
+
+ // Check if the item is wider.
min_width = MAX(min_width, item_size.width);
}
}
@@ -4034,9 +4112,6 @@ int Tree::get_column_width(int p_column) const {
}
}
- if (p_column < columns.size() - 1) {
- column_width += cache.hseparation;
- }
return column_width;
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 8b7ddc3faf..c4a6b6b058 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -95,6 +95,9 @@ private:
bool expand_right = false;
Color icon_color = Color(1, 1, 1);
+ Size2i cached_minimum_size;
+ bool cached_minimum_size_dirty = true;
+
TextAlign text_align = ALIGN_LEFT;
Variant meta;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 05409b7bfe..f5d2d2f2a2 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -70,7 +70,9 @@ void Node::_notification(int p_notification) {
if (data.parent) {
data.process_owner = data.parent->data.process_owner;
} else {
- data.process_owner = nullptr;
+ ERR_PRINT("The root node can't be set to Inherit process mode, reverting to Pausable instead.");
+ data.process_mode = PROCESS_MODE_PAUSABLE;
+ data.process_owner = this;
}
} else {
data.process_owner = this;
@@ -436,18 +438,18 @@ void Node::set_process_mode(ProcessMode p_mode) {
bool prev_can_process = can_process();
bool prev_enabled = _is_enabled();
- data.process_mode = p_mode;
-
- if (data.process_mode == PROCESS_MODE_INHERIT) {
+ if (p_mode == PROCESS_MODE_INHERIT) {
if (data.parent) {
- data.process_owner = data.parent->data.owner;
+ data.process_owner = data.parent->data.process_owner;
} else {
- data.process_owner = nullptr;
+ ERR_FAIL_MSG("The root node can't be set to Inherit process mode.");
}
} else {
data.process_owner = this;
}
+ data.process_mode = p_mode;
+
bool next_can_process = can_process();
bool next_enabled = _is_enabled();
@@ -702,6 +704,9 @@ bool Node::_can_process(bool p_paused) const {
process_mode = data.process_mode;
}
+ // The owner can't be set to inherit, must be a bug.
+ ERR_FAIL_COND_V(process_mode == PROCESS_MODE_INHERIT, false);
+
if (process_mode == PROCESS_MODE_DISABLED) {
return false;
} else if (process_mode == PROCESS_MODE_ALWAYS) {
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index e1b1b356a9..6e78193717 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1322,6 +1322,7 @@ SceneTree::SceneTree() {
// Create with mainloop.
root = memnew(Window);
+ root->set_process_mode(Node::PROCESS_MODE_PAUSABLE);
root->set_name("root");
#ifndef _3D_DISABLED
if (!root->get_world_3d().is_valid()) {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index fb86d37280..b3b743370b 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -35,13 +35,13 @@
#include "core/object/message_queue.h"
#include "core/string/translation.h"
#include "core/templates/pair.h"
+#include "scene/2d/audio_listener_2d.h"
#include "scene/2d/camera_2d.h"
#include "scene/2d/collision_object_2d.h"
-#include "scene/2d/listener_2d.h"
#ifndef _3D_DISABLED
+#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_object_3d.h"
-#include "scene/3d/listener_3d.h"
#include "scene/3d/world_environment.h"
#endif // _3D_DISABLED
#include "scene/gui/control.h"
@@ -381,10 +381,10 @@ void Viewport::_notification(int p_what) {
current_canvas = find_world_2d()->get_canvas();
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
- _update_listener_2d();
+ _update_audio_listener_2d();
#ifndef _3D_DISABLED
RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
- _update_listener_3d();
+ _update_audio_listener_3d();
#endif // _3D_DISABLED
add_to_group("_viewports");
@@ -408,9 +408,9 @@ void Viewport::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
#ifndef _3D_DISABLED
- if (listener_3d_set.size() && !listener_3d) {
- Listener3D *first = nullptr;
- for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) {
+ if (audio_listener_3d_set.size() && !audio_listener_3d) {
+ AudioListener3D *first = nullptr;
+ for (Set<AudioListener3D *>::Element *E = audio_listener_3d_set.front(); E; E = E->next()) {
if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
@@ -822,27 +822,27 @@ Rect2 Viewport::get_visible_rect() const {
return r;
}
-void Viewport::_update_listener_2d() {
+void Viewport::_update_audio_listener_2d() {
if (AudioServer::get_singleton()) {
AudioServer::get_singleton()->notify_listener_changed();
}
}
void Viewport::set_as_audio_listener_2d(bool p_enable) {
- if (p_enable == audio_listener_2d) {
+ if (p_enable == is_audio_listener_2d_enabled) {
return;
}
- audio_listener_2d = p_enable;
- _update_listener_2d();
+ is_audio_listener_2d_enabled = p_enable;
+ _update_audio_listener_2d();
}
bool Viewport::is_audio_listener_2d() const {
- return audio_listener_2d;
+ return is_audio_listener_2d_enabled;
}
-Listener2D *Viewport::get_listener_2d() const {
- return listener_2d;
+AudioListener2D *Viewport::get_audio_listener_2d() const {
+ return audio_listener_2d;
}
void Viewport::enable_canvas_transform_override(bool p_enable) {
@@ -909,18 +909,18 @@ void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
camera_2d = p_camera_2d;
}
-void Viewport::_listener_2d_set(Listener2D *p_listener) {
- if (listener_2d == p_listener) {
+void Viewport::_audio_listener_2d_set(AudioListener2D *p_listener) {
+ if (audio_listener_2d == p_listener) {
return;
- } else if (listener_2d) {
- listener_2d->clear_current();
+ } else if (audio_listener_2d) {
+ audio_listener_2d->clear_current();
}
- listener_2d = p_listener;
+ audio_listener_2d = p_listener;
}
-void Viewport::_listener_2d_remove(Listener2D *p_listener) {
- if (listener_2d == p_listener) {
- listener_2d = nullptr;
+void Viewport::_audio_listener_2d_remove(AudioListener2D *p_listener) {
+ if (audio_listener_2d == p_listener) {
+ audio_listener_2d = nullptr;
}
}
@@ -962,7 +962,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
world_2d = Ref<World2D>(memnew(World2D));
}
- _update_listener_2d();
+ _update_audio_listener_2d();
if (is_inside_tree()) {
current_canvas = find_world_2d()->get_canvas();
@@ -1972,35 +1972,30 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *from = gui.key_focus ? gui.key_focus : nullptr;
- // Keyboard focus.
- Ref<InputEventKey> k = p_event;
- // Need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be.
- bool mods = k.is_valid() && (k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_shift_pressed() || k->is_meta_pressed());
-
if (from && p_event->is_pressed()) {
Control *next = nullptr;
- if (p_event->is_action_pressed("ui_focus_next", true)) {
+ if (p_event->is_action_pressed("ui_focus_next", true, true)) {
next = from->find_next_valid_focus();
}
- if (p_event->is_action_pressed("ui_focus_prev", true)) {
+ if (p_event->is_action_pressed("ui_focus_prev", true, true)) {
next = from->find_prev_valid_focus();
}
- if (!mods && p_event->is_action_pressed("ui_up", true)) {
+ if (p_event->is_action_pressed("ui_up", true, true)) {
next = from->_get_focus_neighbor(SIDE_TOP);
}
- if (!mods && p_event->is_action_pressed("ui_left", true)) {
+ if (p_event->is_action_pressed("ui_left", true, true)) {
next = from->_get_focus_neighbor(SIDE_LEFT);
}
- if (!mods && p_event->is_action_pressed("ui_right", true)) {
+ if (p_event->is_action_pressed("ui_right", true, true)) {
next = from->_get_focus_neighbor(SIDE_RIGHT);
}
- if (!mods && p_event->is_action_pressed("ui_down", true)) {
+ if (p_event->is_action_pressed("ui_down", true, true)) {
next = from->_get_focus_neighbor(SIDE_BOTTOM);
}
@@ -3047,24 +3042,24 @@ Viewport::SDFScale Viewport::get_sdf_scale() const {
}
#ifndef _3D_DISABLED
-Listener3D *Viewport::get_listener_3d() const {
- return listener_3d;
+AudioListener3D *Viewport::get_audio_listener_3d() const {
+ return audio_listener_3d;
}
void Viewport::set_as_audio_listener_3d(bool p_enable) {
- if (p_enable == audio_listener_3d) {
+ if (p_enable == is_audio_listener_3d_enabled) {
return;
}
- audio_listener_3d = p_enable;
- _update_listener_3d();
+ is_audio_listener_3d_enabled = p_enable;
+ _update_audio_listener_3d();
}
bool Viewport::is_audio_listener_3d() const {
- return audio_listener_3d;
+ return is_audio_listener_3d_enabled;
}
-void Viewport::_update_listener_3d() {
+void Viewport::_update_audio_listener_3d() {
if (AudioServer::get_singleton()) {
AudioServer::get_singleton()->notify_listener_changed();
}
@@ -3073,39 +3068,39 @@ void Viewport::_update_listener_3d() {
void Viewport::_listener_transform_3d_changed_notify() {
}
-void Viewport::_listener_3d_set(Listener3D *p_listener) {
- if (listener_3d == p_listener) {
+void Viewport::_audio_listener_3d_set(AudioListener3D *p_listener) {
+ if (audio_listener_3d == p_listener) {
return;
}
- listener_3d = p_listener;
+ audio_listener_3d = p_listener;
- _update_listener_3d();
+ _update_audio_listener_3d();
_listener_transform_3d_changed_notify();
}
-bool Viewport::_listener_3d_add(Listener3D *p_listener) {
- listener_3d_set.insert(p_listener);
- return listener_3d_set.size() == 1;
+bool Viewport::_audio_listener_3d_add(AudioListener3D *p_listener) {
+ audio_listener_3d_set.insert(p_listener);
+ return audio_listener_3d_set.size() == 1;
}
-void Viewport::_listener_3d_remove(Listener3D *p_listener) {
- listener_3d_set.erase(p_listener);
- if (listener_3d == p_listener) {
- listener_3d = nullptr;
+void Viewport::_audio_listener_3d_remove(AudioListener3D *p_listener) {
+ audio_listener_3d_set.erase(p_listener);
+ if (audio_listener_3d == p_listener) {
+ audio_listener_3d = nullptr;
}
}
-void Viewport::_listener_3d_make_next_current(Listener3D *p_exclude) {
- if (listener_3d_set.size() > 0) {
- for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) {
+void Viewport::_audio_listener_3d_make_next_current(AudioListener3D *p_exclude) {
+ if (audio_listener_3d_set.size() > 0) {
+ for (Set<AudioListener3D *>::Element *E = audio_listener_3d_set.front(); E; E = E->next()) {
if (p_exclude == E->get()) {
continue;
}
if (!E->get()->is_inside_tree()) {
continue;
}
- if (listener_3d != nullptr) {
+ if (audio_listener_3d != nullptr) {
return;
}
@@ -3114,7 +3109,7 @@ void Viewport::_listener_3d_make_next_current(Listener3D *p_exclude) {
} else {
// Attempt to reset listener to the camera position.
if (camera_3d != nullptr) {
- _update_listener_3d();
+ _update_audio_listener_3d();
_camera_3d_transform_changed_notify();
}
}
@@ -3168,7 +3163,7 @@ void Viewport::_camera_3d_set(Camera3D *p_camera) {
camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
}
- _update_listener_3d();
+ _update_audio_listener_3d();
_camera_3d_transform_changed_notify();
}
@@ -3330,7 +3325,7 @@ void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
}
- _update_listener_3d();
+ _update_audio_listener_3d();
}
void Viewport::_own_world_3d_changed() {
@@ -3351,7 +3346,7 @@ void Viewport::_own_world_3d_changed() {
RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
}
- _update_listener_3d();
+ _update_audio_listener_3d();
}
void Viewport::set_use_own_world_3d(bool p_world_3d) {
@@ -3385,7 +3380,7 @@ void Viewport::set_use_own_world_3d(bool p_world_3d) {
RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
}
- _update_listener_3d();
+ _update_audio_listener_3d();
}
bool Viewport::is_using_own_world_3d() const {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index bfb52c4b98..3732f9cfd1 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -37,11 +37,11 @@
#ifndef _3D_DISABLED
class Camera3D;
class CollisionObject3D;
-class Listener3D;
+class AudioListener3D;
class World3D;
#endif // _3D_DISABLED
-class Listener2D;
+class AudioListener2D;
class Camera2D;
class CanvasItem;
class CanvasLayer;
@@ -202,7 +202,7 @@ private:
Viewport *parent = nullptr;
- Listener2D *listener_2d = nullptr;
+ AudioListener2D *audio_listener_2d = nullptr;
Camera2D *camera_2d = nullptr;
Set<CanvasLayer *> canvas_layers;
@@ -210,8 +210,8 @@ private:
RID current_canvas;
RID subwindow_canvas;
- bool audio_listener_2d = false;
- RID internal_listener_2d;
+ bool is_audio_listener_2d_enabled = false;
+ RID internal_audio_listener_2d;
bool override_canvas_transform = false;
@@ -274,7 +274,7 @@ private:
StringName unhandled_input_group;
StringName unhandled_key_input_group;
- void _update_listener_2d();
+ void _update_audio_listener_2d();
bool disable_3d = false;
@@ -418,9 +418,9 @@ private:
bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
- friend class Listener2D;
- void _listener_2d_set(Listener2D *p_listener);
- void _listener_2d_remove(Listener2D *p_listener);
+ friend class AudioListener2D;
+ void _audio_listener_2d_set(AudioListener2D *p_listener);
+ void _audio_listener_2d_remove(AudioListener2D *p_listener);
friend class Camera2D;
void _camera_2d_set(Camera2D *p_camera_2d);
@@ -463,7 +463,7 @@ protected:
public:
uint64_t get_processed_events_count() const { return event_count; }
- Listener2D *get_listener_2d() const;
+ AudioListener2D *get_audio_listener_2d() const;
Camera2D *get_camera_2d() const;
void set_as_audio_listener_2d(bool p_enable);
bool is_audio_listener_2d() const;
@@ -593,20 +593,20 @@ public:
#ifndef _3D_DISABLED
bool use_xr = false;
Scale3D scale_3d = SCALE_3D_DISABLED;
- friend class Listener3D;
- Listener3D *listener_3d = nullptr;
- Set<Listener3D *> listener_3d_set;
- bool audio_listener_3d = false;
- RID internal_listener_3d;
- Listener3D *get_listener_3d() const;
+ friend class AudioListener3D;
+ AudioListener3D *audio_listener_3d = nullptr;
+ Set<AudioListener3D *> audio_listener_3d_set;
+ bool is_audio_listener_3d_enabled = false;
+ RID internal_audio_listener_3d;
+ AudioListener3D *get_audio_listener_3d() const;
void set_as_audio_listener_3d(bool p_enable);
bool is_audio_listener_3d() const;
- void _update_listener_3d();
+ void _update_audio_listener_3d();
void _listener_transform_3d_changed_notify();
- void _listener_3d_set(Listener3D *p_listener);
- bool _listener_3d_add(Listener3D *p_listener); //true if first
- void _listener_3d_remove(Listener3D *p_listener);
- void _listener_3d_make_next_current(Listener3D *p_exclude);
+ void _audio_listener_3d_set(AudioListener3D *p_listener);
+ bool _audio_listener_3d_add(AudioListener3D *p_listener); //true if first
+ void _audio_listener_3d_remove(AudioListener3D *p_listener);
+ void _audio_listener_3d_make_next_current(AudioListener3D *p_exclude);
void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 015a4d5dba..1e89b17044 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -36,6 +36,7 @@
#include "core/os/os.h"
#include "scene/2d/animated_sprite_2d.h"
#include "scene/2d/area_2d.h"
+#include "scene/2d/audio_listener_2d.h"
#include "scene/2d/audio_stream_player_2d.h"
#include "scene/2d/back_buffer_copy.h"
#include "scene/2d/camera_2d.h"
@@ -49,7 +50,6 @@
#include "scene/2d/light_2d.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/line_2d.h"
-#include "scene/2d/listener_2d.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/multimesh_instance_2d.h"
#include "scene/2d/navigation_agent_2d.h"
@@ -197,14 +197,15 @@
#include "scene/resources/visual_shader_sdf_nodes.h"
#include "scene/resources/world_2d.h"
#include "scene/resources/world_3d.h"
-#include "scene/resources/world_margin_shape_2d.h"
-#include "scene/resources/world_margin_shape_3d.h"
+#include "scene/resources/world_boundary_shape_2d.h"
+#include "scene/resources/world_boundary_shape_3d.h"
#include "scene/scene_string_names.h"
#include "scene/main/shader_globals_override.h"
#ifndef _3D_DISABLED
#include "scene/3d/area_3d.h"
+#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
@@ -217,7 +218,6 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
-#include "scene/3d/listener_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/navigation_agent_3d.h"
@@ -235,7 +235,7 @@
#include "scene/3d/remote_transform_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/3d/skeleton_ik_3d.h"
-#include "scene/3d/soft_body_3d.h"
+#include "scene/3d/soft_dynamic_body_3d.h"
#include "scene/3d/spring_arm_3d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body_3d.h"
@@ -445,7 +445,7 @@ void register_scene_types() {
GDREGISTER_VIRTUAL_CLASS(GeometryInstance3D);
GDREGISTER_CLASS(Camera3D);
GDREGISTER_CLASS(ClippedCamera3D);
- GDREGISTER_CLASS(Listener3D);
+ GDREGISTER_CLASS(AudioListener3D);
GDREGISTER_CLASS(XRCamera3D);
GDREGISTER_CLASS(XRController3D);
GDREGISTER_CLASS(XRAnchor3D);
@@ -490,13 +490,13 @@ void register_scene_types() {
GDREGISTER_VIRTUAL_CLASS(PhysicsBody3D);
GDREGISTER_CLASS(StaticBody3D);
GDREGISTER_CLASS(AnimatableBody3D);
- GDREGISTER_CLASS(RigidBody3D);
+ GDREGISTER_CLASS(RigidDynamicBody3D);
GDREGISTER_CLASS(KinematicCollision3D);
GDREGISTER_CLASS(CharacterBody3D);
GDREGISTER_CLASS(SpringArm3D);
GDREGISTER_CLASS(PhysicalBone3D);
- GDREGISTER_CLASS(SoftBody3D);
+ GDREGISTER_CLASS(SoftDynamicBody3D);
GDREGISTER_CLASS(SkeletonIK3D);
GDREGISTER_CLASS(BoneAttachment3D);
@@ -650,7 +650,7 @@ void register_scene_types() {
GDREGISTER_VIRTUAL_CLASS(PhysicsBody2D);
GDREGISTER_CLASS(StaticBody2D);
GDREGISTER_CLASS(AnimatableBody2D);
- GDREGISTER_CLASS(RigidBody2D);
+ GDREGISTER_CLASS(RigidDynamicBody2D);
GDREGISTER_CLASS(CharacterBody2D);
GDREGISTER_CLASS(KinematicCollision2D);
GDREGISTER_CLASS(Area2D);
@@ -672,7 +672,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
GDREGISTER_CLASS(Camera2D);
- GDREGISTER_CLASS(Listener2D);
+ GDREGISTER_CLASS(AudioListener2D);
GDREGISTER_VIRTUAL_CLASS(Joint2D);
GDREGISTER_CLASS(PinJoint2D);
GDREGISTER_CLASS(GrooveJoint2D);
@@ -750,7 +750,7 @@ void register_scene_types() {
GDREGISTER_CLASS(CapsuleShape3D);
GDREGISTER_CLASS(CylinderShape3D);
GDREGISTER_CLASS(HeightMapShape3D);
- GDREGISTER_CLASS(WorldMarginShape3D);
+ GDREGISTER_CLASS(WorldBoundaryShape3D);
GDREGISTER_CLASS(ConvexPolygonShape3D);
GDREGISTER_CLASS(ConcavePolygonShape3D);
@@ -831,7 +831,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
GDREGISTER_VIRTUAL_CLASS(Shape2D);
- GDREGISTER_CLASS(WorldMarginShape2D);
+ GDREGISTER_CLASS(WorldBoundaryShape2D);
GDREGISTER_CLASS(SegmentShape2D);
GDREGISTER_CLASS(SeparationRayShape2D);
GDREGISTER_CLASS(CircleShape2D);
@@ -919,8 +919,8 @@ void register_scene_types() {
ClassDB::add_compatibility_class("KinematicBody2D", "CharacterBody2D");
ClassDB::add_compatibility_class("KinematicCollision", "KinematicCollision3D");
ClassDB::add_compatibility_class("Light", "Light3D");
- ClassDB::add_compatibility_class("LineShape2D", "WorldMarginShape2D");
- ClassDB::add_compatibility_class("Listener", "Listener3D");
+ ClassDB::add_compatibility_class("LineShape2D", "WorldBoundaryShape2D");
+ ClassDB::add_compatibility_class("Listener", "AudioListener3D");
ClassDB::add_compatibility_class("MeshInstance", "MeshInstance3D");
ClassDB::add_compatibility_class("MultiMeshInstance", "MultiMeshInstance3D");
ClassDB::add_compatibility_class("NavigationAgent", "NavigationAgent3D");
@@ -950,20 +950,21 @@ void register_scene_types() {
ClassDB::add_compatibility_class("PhysicsServer", "PhysicsServer3D");
ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D");
ClassDB::add_compatibility_class("PinJoint", "PinJoint3D");
- ClassDB::add_compatibility_class("PlaneShape", "WorldMarginShape3D");
+ ClassDB::add_compatibility_class("PlaneShape", "WorldBoundaryShape3D");
ClassDB::add_compatibility_class("ProceduralSky", "Sky");
ClassDB::add_compatibility_class("ProximityGroup", "ProximityGroup3D");
ClassDB::add_compatibility_class("RayCast", "RayCast3D");
ClassDB::add_compatibility_class("RayShape", "SeparationRayShape3D");
ClassDB::add_compatibility_class("RayShape2D", "SeparationRayShape2D");
ClassDB::add_compatibility_class("RemoteTransform", "RemoteTransform3D");
- ClassDB::add_compatibility_class("RigidBody", "RigidBody3D");
+ ClassDB::add_compatibility_class("RigidBody", "RigidDynamicBody3D");
+ ClassDB::add_compatibility_class("RigidBody2D", "RigidDynamicBody2D");
ClassDB::add_compatibility_class("Shape", "Shape3D");
ClassDB::add_compatibility_class("ShortCut", "Shortcut");
ClassDB::add_compatibility_class("Skeleton", "Skeleton3D");
ClassDB::add_compatibility_class("SkeletonIK", "SkeletonIK3D");
ClassDB::add_compatibility_class("SliderJoint", "SliderJoint3D");
- ClassDB::add_compatibility_class("SoftBody", "SoftBody3D");
+ ClassDB::add_compatibility_class("SoftBody", "SoftDynamicBody3D");
ClassDB::add_compatibility_class("Spatial", "Node3D");
ClassDB::add_compatibility_class("SpatialGizmo", "Node3DGizmo");
ClassDB::add_compatibility_class("SpatialMaterial", "StandardMaterial3D");
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index de557494c3..49ed9dcb82 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -48,7 +48,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
img->convert(Image::FORMAT_LA8);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8);
- create(Size2(img->get_width(), img->get_height()));
+ create(img->get_size());
const uint8_t *r = img->get_data().ptr();
uint8_t *w = bitmask.ptrw();
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index 7501efea9e..fa95ab0e79 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -161,7 +161,7 @@ void CanvasItemMaterial::flush_changes() {
void CanvasItemMaterial::_queue_shader_change() {
MutexLock lock(material_mutex);
- if (!element.in_list()) {
+ if (is_initialized && !element.in_list()) {
dirty_materials->add(&element);
}
}
@@ -287,6 +287,7 @@ CanvasItemMaterial::CanvasItemMaterial() :
set_particles_anim_loop(false);
current_key.invalid_key = 1;
+ is_initialized = true;
_queue_shader_change();
}
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index 0a813e0ae5..37cd4de136 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -102,6 +102,7 @@ private:
_FORCE_INLINE_ void _queue_shader_change();
_FORCE_INLINE_ bool _is_shader_dirty() const;
+ bool is_initialized = false;
BlendMode blend_mode = BLEND_MODE_MIX;
LightMode light_mode = LIGHT_MODE_NORMAL;
bool particles_animation = false;
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index fa3824e6eb..492e0512e4 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -51,7 +51,7 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl
} else {
texture = Ref<ImageTexture>(memnew(ImageTexture));
Ref<Image> img = memnew(Image(p_src));
- const Size2 orig_size = Size2(img->get_width(), img->get_height());
+ const Size2 orig_size = img->get_size();
img->convert(Image::FORMAT_RGBA8);
img->resize(orig_size.x * scale, orig_size.y * scale);
@@ -97,7 +97,7 @@ template <class T>
static Ref<Texture2D> make_icon(T p_src) {
Ref<ImageTexture> texture(memnew(ImageTexture));
Ref<Image> img = memnew(Image(p_src));
- const Size2 orig_size = Size2(img->get_width(), img->get_height());
+ const Size2 orig_size = img->get_size();
img->convert(Image::FORMAT_RGBA8);
img->resize(orig_size.x * scale, orig_size.y * scale);
texture->create_from_image(img);
@@ -438,6 +438,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("caret_color", "TextEdit", control_font_color);
theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0));
theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15));
+ theme->set_color("search_result_color", "TextEdit", Color(0.3, 0.3, 0.3));
+ theme->set_color("search_result_border_color", "TextEdit", Color(0.3, 0.3, 0.3, 0.4));
theme->set_constant("line_spacing", "TextEdit", 4 * scale);
theme->set_constant("outline_size", "TextEdit", 0);
@@ -483,6 +485,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("line_number_color", "CodeEdit", Color(0.67, 0.67, 0.67, 0.4));
theme->set_color("word_highlighted_color", "CodeEdit", Color(0.8, 0.9, 0.9, 0.15));
theme->set_color("line_length_guideline_color", "CodeEdit", Color(0.3, 0.5, 0.8, 0.1));
+ theme->set_color("search_result_color", "CodeEdit", Color(0.3, 0.3, 0.3));
+ theme->set_color("search_result_border_color", "CodeEdit", Color(0.3, 0.3, 0.3, 0.4));
theme->set_constant("completion_lines", "CodeEdit", 7);
theme->set_constant("completion_max_width", "CodeEdit", 50);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 7af8e900fd..9b403a18f0 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -689,227 +689,272 @@ void FontData::remove_cache(int p_cache_index) {
}
Array FontData::get_size_cache_list(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_size_cache_list(cache[p_cache_index]);
}
void FontData::clear_size_cache(int p_cache_index) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_size_cache(cache[p_cache_index]);
}
void FontData::remove_size_cache(int p_cache_index, const Vector2i &p_size) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_size_cache(cache[p_cache_index], p_size);
}
void FontData::set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_variation_coordinates(cache[p_cache_index], p_variation_coordinates);
emit_changed();
}
Dictionary FontData::get_variation_coordinates(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Dictionary());
_ensure_rid(p_cache_index);
return TS->font_get_variation_coordinates(cache[p_cache_index]);
}
void FontData::set_ascent(int p_cache_index, int p_size, real_t p_ascent) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_ascent(cache[p_cache_index], p_size, p_ascent);
}
real_t FontData::get_ascent(int p_cache_index, int p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_ascent(cache[p_cache_index], p_size);
}
void FontData::set_descent(int p_cache_index, int p_size, real_t p_descent) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_descent(cache[p_cache_index], p_size, p_descent);
}
real_t FontData::get_descent(int p_cache_index, int p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_descent(cache[p_cache_index], p_size);
}
void FontData::set_underline_position(int p_cache_index, int p_size, real_t p_underline_position) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_underline_position(cache[p_cache_index], p_size, p_underline_position);
}
real_t FontData::get_underline_position(int p_cache_index, int p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_underline_position(cache[p_cache_index], p_size);
}
void FontData::set_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_underline_thickness(cache[p_cache_index], p_size, p_underline_thickness);
}
real_t FontData::get_underline_thickness(int p_cache_index, int p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_underline_thickness(cache[p_cache_index], p_size);
}
void FontData::set_scale(int p_cache_index, int p_size, real_t p_scale) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_scale(cache[p_cache_index], p_size, p_scale);
}
real_t FontData::get_scale(int p_cache_index, int p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_scale(cache[p_cache_index], p_size);
}
void FontData::set_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing, int p_value) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_spacing(cache[p_cache_index], p_size, p_spacing, p_value);
}
int FontData::get_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_spacing(cache[p_cache_index], p_size, p_spacing);
}
int FontData::get_texture_count(int p_cache_index, const Vector2i &p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_texture_count(cache[p_cache_index], p_size);
}
void FontData::clear_textures(int p_cache_index, const Vector2i &p_size) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_textures(cache[p_cache_index], p_size);
}
void FontData::remove_texture(int p_cache_index, const Vector2i &p_size, int p_texture_index) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_texture(cache[p_cache_index], p_size, p_texture_index);
}
void FontData::set_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_texture_image(cache[p_cache_index], p_size, p_texture_index, p_image);
}
Ref<Image> FontData::get_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Ref<Image>());
_ensure_rid(p_cache_index);
return TS->font_get_texture_image(cache[p_cache_index], p_size, p_texture_index);
}
void FontData::set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_texture_offsets(cache[p_cache_index], p_size, p_texture_index, p_offset);
}
PackedInt32Array FontData::get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
_ensure_rid(p_cache_index);
return TS->font_get_texture_offsets(cache[p_cache_index], p_size, p_texture_index);
}
Array FontData::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_list(cache[p_cache_index], p_size);
}
void FontData::clear_glyphs(int p_cache_index, const Vector2i &p_size) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_glyphs(cache[p_cache_index], p_size);
}
void FontData::remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_glyph(cache[p_cache_index], p_size, p_glyph);
}
void FontData::set_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_advance(cache[p_cache_index], p_size, p_glyph, p_advance);
}
Vector2 FontData::get_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_advance(cache[p_cache_index], p_size, p_glyph);
}
void FontData::set_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_offset(cache[p_cache_index], p_size, p_glyph, p_offset);
}
Vector2 FontData::get_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_offset(cache[p_cache_index], p_size, p_glyph);
}
void FontData::set_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_size(cache[p_cache_index], p_size, p_glyph, p_gl_size);
}
Vector2 FontData::get_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_size(cache[p_cache_index], p_size, p_glyph);
}
void FontData::set_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph, p_uv_rect);
}
Rect2 FontData::get_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Rect2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph);
}
void FontData::set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph, p_texture_idx);
}
int FontData::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph);
}
Array FontData::get_kerning_list(int p_cache_index, int p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_kerning_list(cache[p_cache_index], p_size);
}
void FontData::clear_kerning_map(int p_cache_index, int p_size) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_kerning_map(cache[p_cache_index], p_size);
}
void FontData::remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_kerning(cache[p_cache_index], p_size, p_glyph_pair);
}
void FontData::set_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_kerning(cache[p_cache_index], p_size, p_glyph_pair, p_kerning);
}
Vector2 FontData::get_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_kerning(cache[p_cache_index], p_size, p_glyph_pair);
}
void FontData::render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_render_range(cache[p_cache_index], p_size, p_start, p_end);
}
void FontData::render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index) {
+ ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_render_glyph(cache[p_cache_index], p_size, p_index);
}
RID FontData::get_cache_rid(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, RID());
_ensure_rid(p_cache_index);
return cache[p_cache_index];
}
@@ -1008,10 +1053,8 @@ void Font::_data_changed() {
void Font::_ensure_rid(int p_index) const {
// Find or create cache record.
- for (int i = 0; i < rids.size(); i++) {
- if (!rids[i].is_valid() && data[i].is_valid()) {
- rids.write[i] = data[i]->find_cache(variation_coordinates);
- }
+ if (!rids[p_index].is_valid() && data[p_index].is_valid()) {
+ rids.write[p_index] = data[p_index]->find_cache(variation_coordinates);
}
}
@@ -1171,6 +1214,14 @@ void Font::add_data(const Ref<FontData> &p_data) {
if (data[data.size() - 1].is_valid()) {
data.write[data.size() - 1]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
+ Dictionary data_var_list = p_data->get_supported_variation_list();
+ for (int j = 0; j < data_var_list.size(); j++) {
+ int32_t tag = data_var_list.get_key_at_index(j);
+ Vector3i value = data_var_list.get_value_at_index(j);
+ if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
+ variation_coordinates[TS->tag_to_name(tag)] = value.z;
+ }
+ }
}
cache.clear();
@@ -1190,6 +1241,14 @@ void Font::set_data(int p_idx, const Ref<FontData> &p_data) {
data.write[p_idx] = p_data;
rids.write[p_idx] = RID();
+ Dictionary data_var_list = p_data->get_supported_variation_list();
+ for (int j = 0; j < data_var_list.size(); j++) {
+ int32_t tag = data_var_list.get_key_at_index(j);
+ Vector3i value = data_var_list.get_value_at_index(j);
+ if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
+ variation_coordinates[TS->tag_to_name(tag)] = value.z;
+ }
+ }
if (data[p_idx].is_valid()) {
data.write[p_idx]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 05d1a7bf94..fe7124de9e 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -335,9 +335,6 @@ int ImmediateMesh::surface_get_array_len(int p_idx) const {
int ImmediateMesh::surface_get_array_index_len(int p_idx) const {
return 0;
}
-bool ImmediateMesh::surface_is_softbody_friendly(int p_idx) const {
- return false;
-}
Array ImmediateMesh::surface_get_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, int(surfaces.size()), Array());
return RS::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h
index 7010d40719..6673ee6f3d 100644
--- a/scene/resources/immediate_mesh.h
+++ b/scene/resources/immediate_mesh.h
@@ -94,7 +94,6 @@ public:
virtual int get_surface_count() const override;
virtual int surface_get_array_len(int p_idx) const override;
virtual int surface_get_array_index_len(int p_idx) const override;
- virtual bool surface_is_softbody_friendly(int p_idx) const override;
virtual Array surface_get_arrays(int p_surface) const override;
virtual Array surface_get_blend_shape_arrays(int p_surface) const override;
virtual Dictionary surface_get_lods(int p_surface) const override;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 77a68151c4..3a6af3afb0 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -790,12 +790,10 @@ void BaseMaterial3D::_update_shader() {
}
} break;
case BILLBOARD_FIXED_Y: {
- code += " MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)), 0.0),WORLD_MATRIX[3]);\n";
+ code += " MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), CAMERA_MATRIX[2].xyz)),0.0),vec4(0.0, 1.0, 0.0, 0.0),vec4(normalize(cross(CAMERA_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))),0.0),WORLD_MATRIX[3]);\n";
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
- code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, 1.0, 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
- } else {
- code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1.0, 0.0, 0.0, 0.0),vec4(0.0, 1.0/length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0 ,1.0));\n";
+ code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n";
}
} break;
case BILLBOARD_PARTICLES: {
@@ -1303,7 +1301,7 @@ void BaseMaterial3D::flush_changes() {
void BaseMaterial3D::_queue_shader_change() {
MutexLock lock(material_mutex);
- if (!element.in_list()) {
+ if (is_initialized && !element.in_list()) {
dirty_materials->add(&element);
}
}
@@ -2779,6 +2777,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
flags[FLAG_USE_TEXTURE_REPEAT] = true;
+ is_initialized = true;
_queue_shader_change();
}
diff --git a/scene/resources/material.h b/scene/resources/material.h
index e2838e1399..5d7a5324ca 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -440,6 +440,7 @@ private:
_FORCE_INLINE_ void _queue_shader_change();
_FORCE_INLINE_ bool _is_shader_dirty() const;
+ bool is_initialized = false;
bool orm;
Color albedo;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 1edc3ff38b..67db8c1a10 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -38,7 +38,7 @@
#include <stdlib.h>
-Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = nullptr;
+Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (triangle_mesh.is_valid()) {
@@ -156,70 +156,12 @@ void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) {
}
}
-bool Mesh::surface_is_softbody_friendly(int p_idx) const {
- const uint32_t surface_format = surface_get_format(p_idx);
- return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE);
-}
-
Vector<Face3> Mesh::get_faces() const {
Ref<TriangleMesh> tm = generate_triangle_mesh();
if (tm.is_valid()) {
return tm->get_faces();
}
return Vector<Face3>();
- /*
- for (int i=0;i<surfaces.size();i++) {
- if (RenderingServer::get_singleton()->mesh_surface_get_primitive_type( mesh, i ) != RenderingServer::PRIMITIVE_TRIANGLES )
- continue;
-
- Vector<int> indices;
- Vector<Vector3> vertices;
-
- vertices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_VERTEX);
-
- int len=RenderingServer::get_singleton()->mesh_surface_get_array_index_len(mesh, i);
- bool has_indices;
-
- if (len>0) {
- indices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_INDEX);
- has_indices=true;
-
- } else {
- len=vertices.size();
- has_indices=false;
- }
-
- if (len<=0)
- continue;
-
- const int* indicesr = indices.ptr();
- const int *indicesptr = indicesr.ptr();
-
- const Vector3* verticesr = vertices.ptr();
- const Vector3 *verticesptr = verticesr.ptr();
-
- int old_faces=faces.size();
- int new_faces=old_faces+(len/3);
-
- faces.resize(new_faces);
-
- Face3* facesw = faces.ptrw();
- Face3 *facesptr=facesw.ptr();
-
-
- for (int i=0;i<len/3;i++) {
- Face3 face;
-
- for (int j=0;j<3;j++) {
- int idx=i*3+j;
- face.vertex[j] = has_indices ? verticesptr[ indicesptr[ idx ] ] : verticesptr[idx];
- }
-
- facesptr[i+old_faces]=face;
- }
-
- }
-*/
}
Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
@@ -568,35 +510,36 @@ void Mesh::clear_cache() const {
}
Vector<Ref<Shape3D>> Mesh::convex_decompose(const ConvexDecompositionSettings &p_settings) const {
- ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape3D>>());
+ ERR_FAIL_COND_V(!convex_decomposition_function, Vector<Ref<Shape3D>>());
- const Vector<Face3> faces = get_faces();
-
- const Vector<Vector<Face3>> decomposed = convex_composition_function(faces, p_settings);
+ Ref<TriangleMesh> tm = generate_triangle_mesh();
+ ERR_FAIL_COND_V(!tm.is_valid(), Vector<Ref<Shape3D>>());
- Vector<Ref<Shape3D>> ret;
+ const Vector<TriangleMesh::Triangle> &triangles = tm->get_triangles();
+ int triangle_count = triangles.size();
- for (int i = 0; i < decomposed.size(); i++) {
- Set<Vector3> points;
- for (int j = 0; j < decomposed[i].size(); j++) {
- points.insert(decomposed[i][j].vertex[0]);
- points.insert(decomposed[i][j].vertex[1]);
- points.insert(decomposed[i][j].vertex[2]);
- }
-
- Vector<Vector3> convex_points;
- convex_points.resize(points.size());
- {
- Vector3 *w = convex_points.ptrw();
- int idx = 0;
- for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
- w[idx++] = E->get();
+ Vector<uint32_t> indices;
+ {
+ indices.resize(triangle_count * 3);
+ uint32_t *w = indices.ptrw();
+ for (int i = 0; i < triangle_count; i++) {
+ for (int j = 0; j < 3; j++) {
+ w[i * 3 + j] = triangles[i].indices[j];
}
}
+ }
+
+ const Vector<Vector3> &vertices = tm->get_vertices();
+ int vertex_count = vertices.size();
+ Vector<Vector<Vector3>> decomposed = convex_decomposition_function((real_t *)vertices.ptr(), vertex_count, indices.ptr(), triangle_count, p_settings, nullptr);
+
+ Vector<Ref<Shape3D>> ret;
+
+ for (int i = 0; i < decomposed.size(); i++) {
Ref<ConvexPolygonShape3D> shape;
shape.instantiate();
- shape->set_points(convex_points);
+ shape->set_points(decomposed[i]);
ret.push_back(shape);
}
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 4d0ee0f247..8d5571d67c 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -132,7 +132,6 @@ public:
virtual int get_surface_count() const = 0;
virtual int surface_get_array_len(int p_idx) const = 0;
virtual int surface_get_array_index_len(int p_idx) const = 0;
- virtual bool surface_is_softbody_friendly(int p_idx) const;
virtual Array surface_get_arrays(int p_surface) const = 0;
virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0;
virtual Dictionary surface_get_lods(int p_surface) const = 0;
@@ -191,9 +190,9 @@ public:
uint32_t max_convex_hulls = 1;
bool project_hull_vertices = true;
};
- typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &p_faces, const ConvexDecompositionSettings &p_settings);
+ typedef Vector<Vector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const ConvexDecompositionSettings &p_settings, Vector<Vector<uint32_t>> *r_convex_indices);
- static ConvexDecompositionFunc convex_composition_function;
+ static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index e74f759855..59faa50114 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -99,8 +99,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
#endif
parent = nparent;
} else {
- // i == 0 is root node. Confirm that it doesn't have a parent defined.
+ // i == 0 is root node.
ERR_FAIL_COND_V_MSG(n.parent != -1, nullptr, vformat("Invalid scene: root node %s cannot specify a parent node.", snames[n.name]));
+ ERR_FAIL_COND_V_MSG(n.type == TYPE_INSTANCED && base_scene_idx < 0, nullptr, vformat("Invalid scene: root node %s in an instance, but there's no base scene.", snames[n.name]));
}
Node *node = nullptr;
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 0495a9e92c..d9ec0bfd69 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -741,7 +741,7 @@ void ParticlesMaterial::flush_changes() {
void ParticlesMaterial::_queue_shader_change() {
MutexLock lock(material_mutex);
- if (!element.in_list()) {
+ if (is_initialized && !element.in_list()) {
dirty_materials->add(&element);
}
}
@@ -1533,6 +1533,7 @@ ParticlesMaterial::ParticlesMaterial() :
current_key.invalid_key = 1;
+ is_initialized = true;
_queue_shader_change();
}
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 8ab26aff77..36bc456978 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -226,6 +226,7 @@ private:
_FORCE_INLINE_ void _queue_shader_change();
_FORCE_INLINE_ bool _is_shader_dirty() const;
+ bool is_initialized = false;
Vector3 direction;
float spread;
float flatness;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index e7da41db9d..f8be00f5fb 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -1390,6 +1390,12 @@ void QuadMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset");
}
+uint32_t QuadMesh::surface_get_format(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, 1, 0);
+
+ return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV;
+}
+
QuadMesh::QuadMesh() {
primitive_type = PRIMITIVE_TRIANGLES;
}
@@ -1460,7 +1466,7 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const {
} else {
Vector3 p = Vector3(x * radius * w, y, z * radius * w);
points.push_back(p);
- Vector3 normal = Vector3(x * radius * w * scale, y / scale, z * radius * w * scale);
+ Vector3 normal = Vector3(x * w * scale, radius * (y / scale), z * w * scale);
normals.push_back(normal.normalized());
};
ADD_TANGENT(z, 0.0, -x, 1.0)
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 7915cb0028..d447dad97a 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -285,6 +285,8 @@ protected:
virtual void _create_mesh_array(Array &p_arr) const override;
public:
+ virtual uint32_t surface_get_format(int p_idx) const override;
+
QuadMesh();
void set_size(const Size2 &p_size);
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
index e533fb054a..7ac40b497d 100644
--- a/scene/resources/skeleton_modification_2d.cpp
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -96,37 +96,25 @@ float SkeletonModification2D::clamp_angle(float p_angle, float p_min_bound, floa
p_max_bound = Math_TAU + p_max_bound;
}
if (p_min_bound > p_max_bound) {
- float tmp = p_min_bound;
- p_min_bound = p_max_bound;
- p_max_bound = tmp;
+ SWAP(p_min_bound, p_max_bound);
}
+ bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound);
+ bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound);
+
// Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
- if (p_invert == false) {
- if (p_angle < p_min_bound || p_angle > p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
- }
- } else {
- if (p_angle > p_min_bound && p_angle < p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
+ if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) {
+ Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
+ Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
+ Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
+ if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
+ p_angle = p_min_bound;
+ } else {
+ p_angle = p_max_bound;
}
}
+
return p_angle;
}
@@ -152,9 +140,7 @@ void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_b
arc_angle_max = (Math_PI * 2) + arc_angle_max;
}
if (arc_angle_min > arc_angle_max) {
- float tmp = arc_angle_min;
- arc_angle_min = arc_angle_max;
- arc_angle_max = tmp;
+ SWAP(arc_angle_min, arc_angle_max);
}
arc_angle_min += p_operation_bone->get_bone_angle();
arc_angle_max += p_operation_bone->get_bone_angle();
diff --git a/scene/resources/skeleton_modification_2d_fabrik.cpp b/scene/resources/skeleton_modification_2d_fabrik.cpp
index 6e9429034f..3b5c555f89 100644
--- a/scene/resources/skeleton_modification_2d_fabrik.cpp
+++ b/scene/resources/skeleton_modification_2d_fabrik.cpp
@@ -247,7 +247,7 @@ void SkeletonModification2DFABRIK::chain_backwards() {
}
float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y);
- float length = current_bone2d_node_length / (previous_pose.get_origin() - current_pose.get_origin()).length();
+ float length = current_bone2d_node_length / (current_pose.get_origin().distance_to(previous_pose.get_origin()));
Vector2 finish_position = previous_pose.get_origin().lerp(current_pose.get_origin(), length);
current_pose.set_origin(finish_position);
@@ -268,7 +268,7 @@ void SkeletonModification2DFABRIK::chain_forwards() {
Transform2D next_pose = fabrik_transform_chain[i + 1];
float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y);
- float length = current_bone2d_node_length / (current_pose.get_origin() - next_pose.get_origin()).length();
+ float length = current_bone2d_node_length / (next_pose.get_origin().distance_to(current_pose.get_origin()));
Vector2 finish_position = current_pose.get_origin().lerp(next_pose.get_origin(), length);
current_pose.set_origin(finish_position);
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index 88d80a501f..4f752896a9 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -144,7 +144,7 @@ void SkeletonModification2DTwoBoneIK::_execute(float p_delta) {
// With modifications by TwistedTwigleg
Vector2 target_difference = target->get_global_position() - joint_one_bone->get_global_position();
float joint_one_to_target = target_difference.length();
- float angle_atan = Math::atan2(target_difference.y, target_difference.x);
+ float angle_atan = target_difference.angle();
float bone_one_length = joint_one_bone->get_length() * MIN(joint_one_bone->get_global_scale().x, joint_one_bone->get_global_scale().y);
float bone_two_length = joint_two_bone->get_length() * MIN(joint_two_bone->get_global_scale().x, joint_two_bone->get_global_scale().y);
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
index ee02ede2d5..b476952d86 100644
--- a/scene/resources/skeleton_modification_3d.cpp
+++ b/scene/resources/skeleton_modification_3d.cpp
@@ -72,37 +72,25 @@ real_t SkeletonModification3D::clamp_angle(real_t p_angle, real_t p_min_bound, r
p_max_bound = Math_TAU + p_max_bound;
}
if (p_min_bound > p_max_bound) {
- real_t tmp = p_min_bound;
- p_min_bound = p_max_bound;
- p_max_bound = tmp;
+ SWAP(p_min_bound, p_max_bound);
}
+ bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound);
+ bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound);
+
// Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
- if (p_invert == false) {
- if (p_angle < p_min_bound || p_angle > p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
- }
- } else {
- if (p_angle > p_min_bound && p_angle < p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
+ if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) {
+ Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
+ Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
+ Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
+
+ if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
+ p_angle = p_min_bound;
+ } else {
+ p_angle = p_max_bound;
}
}
+
return p_angle;
}
diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp
index 69f75eb7b5..e615615924 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.cpp
+++ b/scene/resources/skeleton_modification_3d_fabrik.cpp
@@ -232,7 +232,7 @@ void SkeletonModification3DFABRIK::chain_backwards() {
int current_bone_idx = fabrik_data_chain[i].bone_idx;
Transform3D current_trans = stack->skeleton->local_pose_to_global_pose(current_bone_idx, stack->skeleton->get_bone_local_pose_override(current_bone_idx));
- real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin - current_trans.origin).length();
+ real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin));
current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length);
// Apply it back to the skeleton
@@ -253,7 +253,7 @@ void SkeletonModification3DFABRIK::chain_forwards() {
int next_bone_idx = fabrik_data_chain[i + 1].bone_idx;
Transform3D next_bone_trans = stack->skeleton->local_pose_to_global_pose(next_bone_idx, stack->skeleton->get_bone_local_pose_override(next_bone_idx));
- real_t length = fabrik_data_chain[i].length / (current_trans.origin - next_bone_trans.origin).length();
+ real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin));
next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length);
// Apply it back to the skeleton
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index d5e370568d..a8cd872408 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -1176,6 +1176,7 @@ Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_coun
ERR_FAIL_COND_V(simplify_func == nullptr, lod);
ERR_FAIL_COND_V(vertex_array.size() == 0, lod);
ERR_FAIL_COND_V(index_array.size() == 0, lod);
+ ERR_FAIL_COND_V(index_array.size() % 3 != 0, lod);
lod.resize(index_array.size());
LocalVector<float> vertices; //uses floats
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 3dc32632cc..80cab99373 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -1248,6 +1248,14 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
return atlas->is_pixel_opaque(x, y);
}
+Ref<Image> AtlasTexture::get_image() const {
+ if (!atlas.is_valid()) {
+ return Ref<Image>();
+ }
+
+ return atlas->get_image()->get_rect(region);
+}
+
AtlasTexture::AtlasTexture() {}
/////////////////////////////////////////
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 93f4e2de5a..862b9a47a6 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -250,6 +250,8 @@ public:
bool is_pixel_opaque(int p_x, int p_y) const override;
+ virtual Ref<Image> get_image() const override;
+
AtlasTexture();
};
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 918fc3fe9c..5a8c5b3782 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1019,20 +1019,25 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() {
void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) {
if (tile_meshes_dirty) {
- Vector<Vector2> uvs = get_tile_shape_polygon();
+ Vector<Vector2> shape = get_tile_shape_polygon();
+ Vector<Vector2> uvs;
+ uvs.resize(shape.size());
+ for (int i = 0; i < shape.size(); i++) {
+ uvs.write[i] = shape[i] + Vector2(0.5, 0.5);
+ }
Vector<Color> colors;
- colors.resize(uvs.size());
+ colors.resize(shape.size());
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
// Filled mesh.
tile_filled_mesh->clear_surfaces();
Array a;
a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = uvs;
+ a[Mesh::ARRAY_VERTEX] = shape;
a[Mesh::ARRAY_TEX_UV] = uvs;
a[Mesh::ARRAY_COLOR] = colors;
- a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(uvs);
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(shape);
tile_filled_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
// Lines mesh.
@@ -1040,9 +1045,9 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform
a.clear();
a.resize(Mesh::ARRAY_MAX);
// Add the first point again when drawing lines.
- uvs.push_back(uvs[0]);
+ shape.push_back(shape[0]);
colors.push_back(colors[0]);
- a[Mesh::ARRAY_VERTEX] = uvs;
+ a[Mesh::ARRAY_VERTEX] = shape;
a[Mesh::ARRAY_COLOR] = colors;
tile_lines_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
@@ -3119,7 +3124,7 @@ Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
}
bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) {
- Vector<String> components = String(p_name).split("/", true, 2);
+ Vector<String> components = String(p_name).split("/", true, 3);
// Compute the vector2i if we have coordinates.
Vector<String> coords_split = components[0].split(":");
@@ -3138,8 +3143,32 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value)
// Properties.
if (components[1] == "size_in_atlas") {
move_tile_in_atlas(coords, coords, p_value);
+ return true;
} else if (components[1] == "next_alternative_id") {
tiles[coords].next_alternative_id = p_value;
+ return true;
+ } else if (components[1] == "animation_columns") {
+ set_tile_animation_columns(coords, p_value);
+ return true;
+ } else if (components[1] == "animation_separation") {
+ set_tile_animation_separation(coords, p_value);
+ return true;
+ } else if (components[1] == "animation_speed") {
+ set_tile_animation_speed(coords, p_value);
+ return true;
+ } else if (components[1] == "animation_frames_count") {
+ set_tile_animation_frames_count(coords, p_value);
+ return true;
+ } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[1].trim_prefix("animation_frame_").to_int();
+ if (components[2] == "duration") {
+ if (frame >= get_tile_animation_frames_count(coords)) {
+ set_tile_animation_frames_count(coords, frame + 1);
+ }
+ set_tile_animation_frame_duration(coords, frame, p_value);
+ return true;
+ }
+ return false;
} else if (components[1].is_valid_int()) {
int alternative_id = components[1].to_int();
if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
@@ -3185,6 +3214,28 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
} else if (components[1] == "next_alternative_id") {
r_ret = tiles[coords].next_alternative_id;
return true;
+ } else if (components[1] == "animation_columns") {
+ r_ret = get_tile_animation_columns(coords);
+ return true;
+ } else if (components[1] == "animation_separation") {
+ r_ret = get_tile_animation_separation(coords);
+ return true;
+ } else if (components[1] == "animation_speed") {
+ r_ret = get_tile_animation_speed(coords);
+ return true;
+ } else if (components[1] == "animation_frames_count") {
+ r_ret = get_tile_animation_frames_count(coords);
+ return true;
+ } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[1].trim_prefix("animation_frame_").to_int();
+ if (frame < 0 || frame >= get_tile_animation_frames_count(coords)) {
+ return false;
+ }
+ if (components[2] == "duration") {
+ r_ret = get_tile_animation_frame_duration(coords, frame);
+ return true;
+ }
+ return false;
} else if (components[1].is_valid_int()) {
int alternative_id = components[1].to_int();
if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) {
@@ -3226,6 +3277,40 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
}
tile_property_list.push_back(property_info);
+ // animation_columns.
+ property_info = PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().animation_columns == 0) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ // animation_separation.
+ property_info = PropertyInfo(Variant::INT, "animation_separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().animation_separation == Vector2i()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ // animation_speed.
+ property_info = PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().animation_speed == 1.0) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ // animation_frames_count.
+ tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NETWORK));
+
+ // animation_frame_*.
+ bool store_durations = tiles[E_tile->key()].animation_frames_durations.size() >= 2;
+ for (int i = 0; i < (int)tiles[E_tile->key()].animation_frames_durations.size(); i++) {
+ property_info = PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (!store_durations) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+ }
+
for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) {
// Add a dummy property to show the alternative exists.
tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
@@ -3234,11 +3319,10 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> alternative_property_list;
E_alternative->get()->get_property_list(&alternative_property_list);
for (PropertyInfo &alternative_property_info : alternative_property_list) {
- bool valid;
- Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name, &valid);
+ Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name);
Variant value = E_alternative->get()->get(alternative_property_info.name);
- if (valid && value == default_value) {
- property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
+ alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative->key()), alternative_property_info.name);
tile_property_list.push_back(alternative_property_info);
@@ -3257,33 +3341,27 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector
// Create a tile if it does not exists.
ERR_FAIL_COND(p_atlas_coords.x < 0 || p_atlas_coords.y < 0);
ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
- for (int x = 0; x < p_size.x; x++) {
- for (int y = 0; y < p_size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- ERR_FAIL_COND_MSG(tiles.has(coords), vformat("Cannot create tile at position %s with size %s. Already a tile present at %s.", p_atlas_coords, p_size, coords));
- }
- }
+
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, p_size, 1, Vector2i(), 1);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile, tiles are already present in the space the tile would cover.");
+
+ // Initialize the tile data.
+ TileAlternativesData tad;
+ tad.size_in_atlas = p_size;
+ tad.animation_frames_durations.push_back(1.0);
+ tad.alternatives[0] = memnew(TileData);
+ tad.alternatives[0]->set_tile_set(tile_set);
+ tad.alternatives[0]->set_allow_transform(false);
+ tad.alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
+ tad.alternatives[0]->notify_property_list_changed();
+ tad.alternatives_ids.append(0);
// Create and resize the tile.
- tiles.insert(p_atlas_coords, TileSetAtlasSource::TileAlternativesData());
+ tiles.insert(p_atlas_coords, tad);
tiles_ids.append(p_atlas_coords);
tiles_ids.sort();
- tiles[p_atlas_coords].size_in_atlas = p_size;
- tiles[p_atlas_coords].alternatives[0] = memnew(TileData);
- tiles[p_atlas_coords].alternatives[0]->set_tile_set(tile_set);
- tiles[p_atlas_coords].alternatives[0]->set_allow_transform(false);
- tiles[p_atlas_coords].alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
- tiles[p_atlas_coords].alternatives[0]->notify_property_list_changed();
- tiles[p_atlas_coords].alternatives_ids.append(0);
-
- // Add all covered positions to the mapping cache
- for (int x = 0; x < p_size.x; x++) {
- for (int y = 0; y < p_size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache[coords] = p_atlas_coords;
- }
- }
+ _create_coords_mapping_cache(p_atlas_coords);
emit_signal(SNAME("changed"));
}
@@ -3292,14 +3370,7 @@ void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
// Remove all covered positions from the mapping cache
- Size2i size = tiles[p_atlas_coords].size_in_atlas;
-
- for (int x = 0; x < size.x; x++) {
- for (int y = 0; y < size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache.erase(coords);
- }
- }
+ _clear_coords_mapping_cache(p_atlas_coords);
// Free tile data.
for (Map<int, TileData *>::Element *E_tile_data = tiles[p_atlas_coords].alternatives.front(); E_tile_data; E_tile_data = E_tile_data->next()) {
@@ -3326,6 +3397,118 @@ Vector2i TileSetAtlasSource::get_tile_at_coords(Vector2i p_atlas_coords) const {
return _coords_mapping_cache[p_atlas_coords];
}
+void TileSetAtlasSource::set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_frame_columns < 0);
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, p_frame_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
+
+ _clear_coords_mapping_cache(p_atlas_coords);
+
+ tiles[p_atlas_coords].animation_columns = p_frame_columns;
+
+ _create_coords_mapping_cache(p_atlas_coords);
+
+ emit_signal(SNAME("changed"));
+}
+
+int TileSetAtlasSource::get_tile_animation_columns(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_columns;
+}
+
+void TileSetAtlasSource::set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_separation.x < 0 || p_separation.y < 0);
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, p_separation, tad.animation_frames_durations.size(), p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
+
+ _clear_coords_mapping_cache(p_atlas_coords);
+
+ tiles[p_atlas_coords].animation_separation = p_separation;
+
+ _create_coords_mapping_cache(p_atlas_coords);
+
+ emit_signal(SNAME("changed"));
+}
+
+Vector2i TileSetAtlasSource::get_tile_animation_separation(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_separation;
+}
+
+void TileSetAtlasSource::set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_speed <= 0);
+
+ tiles[p_atlas_coords].animation_speed = p_speed;
+
+ emit_signal(SNAME("changed"));
+}
+
+real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1.0, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_speed;
+}
+
+void TileSetAtlasSource::set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_frames_count < 1);
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, tad.animation_separation, p_frames_count, p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
+
+ _clear_coords_mapping_cache(p_atlas_coords);
+
+ int old_size = tiles[p_atlas_coords].animation_frames_durations.size();
+ tiles[p_atlas_coords].animation_frames_durations.resize(p_frames_count);
+ for (int i = old_size; i < p_frames_count; i++) {
+ tiles[p_atlas_coords].animation_frames_durations[i] = 1.0;
+ }
+
+ _create_coords_mapping_cache(p_atlas_coords);
+
+ notify_property_list_changed();
+
+ emit_signal(SNAME("changed"));
+}
+
+int TileSetAtlasSource::get_tile_animation_frames_count(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_frames_durations.size();
+}
+
+void TileSetAtlasSource::set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_INDEX(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size());
+ ERR_FAIL_COND(p_duration <= 0.0);
+
+ tiles[p_atlas_coords].animation_frames_durations[p_frame_index] = p_duration;
+
+ emit_signal(SNAME("changed"));
+}
+
+real_t TileSetAtlasSource::get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_INDEX_V(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size(), 0.0);
+ return tiles[p_atlas_coords].animation_frames_durations[p_frame_index];
+}
+
+real_t TileSetAtlasSource::get_tile_animation_total_duration(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+
+ real_t sum = 0.0;
+ for (int frame = 0; frame < (int)tiles[p_atlas_coords].animation_frames_durations.size(); frame++) {
+ sum += tiles[p_atlas_coords].animation_frames_durations[frame];
+ }
+ return sum;
+}
+
Vector2i TileSetAtlasSource::get_tile_size_in_atlas(Vector2i p_atlas_coords) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(-1, -1), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
@@ -3341,16 +3524,46 @@ Vector2i TileSetAtlasSource::get_tile_id(int p_index) const {
return tiles_ids[p_index];
}
-Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords) const {
+bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile) const {
+ if (p_atlas_coords.x < 0 || p_atlas_coords.y < 0) {
+ return false;
+ }
+ if (p_size.x <= 0 || p_size.y <= 0) {
+ return false;
+ }
+ Size2i atlas_grid_size = get_atlas_grid_size();
+ for (int frame = 0; frame < p_frames_count; frame++) {
+ Vector2i frame_coords = p_atlas_coords + (p_size + p_animation_separation) * ((p_animation_columns > 0) ? Vector2i(frame % p_animation_columns, frame / p_animation_columns) : Vector2i(frame, 0));
+ for (int x = 0; x < p_size.x; x++) {
+ for (int y = 0; y < p_size.y; y++) {
+ Vector2i coords = frame_coords + Vector2i(x, y);
+ if (_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] != p_ignored_tile) {
+ return false;
+ }
+ if (coords.x >= atlas_grid_size.x || coords.y >= atlas_grid_size.y) {
+ if (!(_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] == p_ignored_tile)) {
+ return false; // Only accept tiles outside the atlas if they are part of the ignored tile.
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i());
+
+ const TileAlternativesData &tad = tiles[p_atlas_coords];
- Vector2i size_in_atlas = tiles[p_atlas_coords].size_in_atlas;
+ Vector2i size_in_atlas = tad.size_in_atlas;
Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
- Vector2 origin = margins + (p_atlas_coords * (texture_region_size + separation));
+ Vector2i frame_coords = p_atlas_coords + (size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0));
+ Vector2 origin = margins + (frame_coords * (texture_region_size + separation));
return Rect2(origin, region_size);
- ;
}
Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const {
@@ -3362,63 +3575,29 @@ Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_
margin = Vector2i(MAX(0, margin.x), MAX(0, margin.y));
Vector2i effective_texture_offset = Object::cast_to<TileData>(get_tile_data(p_atlas_coords, p_alternative_tile))->get_texture_offset();
if (ABS(effective_texture_offset.x) > margin.x || ABS(effective_texture_offset.y) > margin.y) {
- effective_texture_offset.x = CLAMP(effective_texture_offset.x, -margin.x, margin.x);
- effective_texture_offset.y = CLAMP(effective_texture_offset.y, -margin.y, margin.y);
+ effective_texture_offset = effective_texture_offset.clamp(-margin, margin);
}
return effective_texture_offset;
}
-bool TileSetAtlasSource::can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) const {
- ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
-
- Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
- if (new_atlas_coords.x < 0 || new_atlas_coords.y < 0) {
- return false;
- }
-
- Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas;
- ERR_FAIL_COND_V(size.x <= 0 || size.y <= 0, false);
-
- Size2i grid_size = get_atlas_grid_size();
- if (new_atlas_coords.x + size.x > grid_size.x || new_atlas_coords.y + size.y > grid_size.y) {
- return false;
- }
-
- Rect2i new_rect = Rect2i(new_atlas_coords, size);
- // Check if the new tile can fit in the new rect.
- for (int x = new_rect.position.x; x < new_rect.get_end().x; x++) {
- for (int y = new_rect.position.y; y < new_rect.get_end().y; y++) {
- Vector2i coords = get_tile_at_coords(Vector2i(x, y));
- if (coords != p_atlas_coords && coords != TileSetSource::INVALID_ATLAS_COORDS) {
- return false;
- }
- }
- }
-
- return true;
-}
-
void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) {
- bool can_move = can_move_tile_in_atlas(p_atlas_coords, p_new_atlas_coords, p_new_size);
- ERR_FAIL_COND_MSG(!can_move, vformat("Cannot move tile at position %s with size %s. Tile already present.", p_new_atlas_coords, p_new_size));
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
// Compute the actual new rect from arguments.
Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
- Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas;
+ Vector2i new_size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tad.size_in_atlas;
- if (new_atlas_coords == p_atlas_coords && size == tiles[p_atlas_coords].size_in_atlas) {
+ if (new_atlas_coords == p_atlas_coords && new_size == tad.size_in_atlas) {
return;
}
- // Remove all covered positions from the mapping cache.
- Size2i old_size = tiles[p_atlas_coords].size_in_atlas;
- for (int x = 0; x < old_size.x; x++) {
- for (int y = 0; y < old_size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache.erase(coords);
- }
- }
+ bool room_for_tile = has_room_for_tile(new_atlas_coords, new_size, tad.animation_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, vformat("Cannot move tile at position %s with size %s. Tile already present.", new_atlas_coords, new_size));
+
+ _clear_coords_mapping_cache(p_atlas_coords);
// Move the tile and update its size.
if (new_atlas_coords != p_atlas_coords) {
@@ -3429,15 +3608,9 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_
tiles_ids.append(new_atlas_coords);
tiles_ids.sort();
}
- tiles[new_atlas_coords].size_in_atlas = size;
+ tiles[new_atlas_coords].size_in_atlas = new_size;
- // Add all covered positions to the mapping cache again.
- for (int x = 0; x < size.x; x++) {
- for (int y = 0; y < size.y; y++) {
- Vector2i coords = new_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache[coords] = new_atlas_coords;
- }
- }
+ _create_coords_mapping_cache(new_atlas_coords);
emit_signal(SNAME("changed"));
}
@@ -3566,12 +3739,25 @@ void TileSetAtlasSource::_bind_methods() {
// Base tiles
ClassDB::bind_method(D_METHOD("create_tile", "atlas_coords", "size"), &TileSetAtlasSource::create_tile, DEFVAL(Vector2i(1, 1)));
ClassDB::bind_method(D_METHOD("remove_tile", "atlas_coords"), &TileSetAtlasSource::remove_tile); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
- ClassDB::bind_method(D_METHOD("can_move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::can_move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
ClassDB::bind_method(D_METHOD("move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas);
+ ClassDB::bind_method(D_METHOD("has_room_for_tile", "atlas_coords", "size", "animation_columns", "animation_separation", "frames_count", "ignored_tile"), &TileSetAtlasSource::has_room_for_tile, DEFVAL(INVALID_ATLAS_COORDS));
+
ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_columns", "atlas_coords", "frame_columns"), &TileSetAtlasSource::set_tile_animation_columns);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_columns", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_columns);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_separation", "atlas_coords", "separation"), &TileSetAtlasSource::set_tile_animation_separation);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_separation", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_separation);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_speed", "atlas_coords", "speed"), &TileSetAtlasSource::set_tile_animation_speed);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_speed", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_speed);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_frames_count", "atlas_coords", "frames_count"), &TileSetAtlasSource::set_tile_animation_frames_count);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_frames_count", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_frames_count);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_frame_duration", "atlas_coords", "frame_index", "duration"), &TileSetAtlasSource::set_tile_animation_frame_duration);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_frame_duration", "atlas_coords", "frame_index"), &TileSetAtlasSource::get_tile_animation_frame_duration);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_total_duration", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_total_duration);
+
// Alternative tiles
ClassDB::bind_method(D_METHOD("create_alternative_tile", "atlas_coords", "alternative_id_override"), &TileSetAtlasSource::create_alternative_tile, DEFVAL(INVALID_TILE_ALTERNATIVE));
ClassDB::bind_method(D_METHOD("remove_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::remove_alternative_tile);
@@ -3584,7 +3770,7 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size);
ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture);
ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture);
- ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords"), &TileSetAtlasSource::get_tile_texture_region);
+ ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0));
}
TileSetAtlasSource::~TileSetAtlasSource() {
@@ -3618,6 +3804,45 @@ void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coo
};
}
+void TileSetAtlasSource::_clear_coords_mapping_cache(Vector2i p_atlas_coords) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
+ Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
+ for (int x = 0; x < tad.size_in_atlas.x; x++) {
+ for (int y = 0; y < tad.size_in_atlas.y; y++) {
+ Vector2i coords = frame_coords + Vector2i(x, y);
+ if (!_coords_mapping_cache.has(coords)) {
+ WARN_PRINT(vformat("TileSetAtlasSource has no cached tile at position %s, the position cache might be corrupted.", coords));
+ } else {
+ if (_coords_mapping_cache[coords] != p_atlas_coords) {
+ WARN_PRINT(vformat("The position cache at position %s is pointing to a wrong tile, the position cache might be corrupted.", coords));
+ }
+ _coords_mapping_cache.erase(coords);
+ }
+ }
+ }
+ }
+}
+
+void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
+ Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
+ for (int x = 0; x < tad.size_in_atlas.x; x++) {
+ for (int y = 0; y < tad.size_in_atlas.y; y++) {
+ Vector2i coords = frame_coords + Vector2i(x, y);
+ if (_coords_mapping_cache.has(coords)) {
+ WARN_PRINT(vformat("The cache already has a tile for position %s, the position cache might be corrupted.", coords));
+ }
+ _coords_mapping_cache[coords] = p_atlas_coords;
+ }
+ }
+ }
+}
+
/////////////////////////////// TileSetScenesCollectionSource //////////////////////////////////////
void TileSetScenesCollectionSource::_compute_next_alternative_id() {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index ba7207241a..46cb1fb36d 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -447,16 +447,23 @@ public:
class TileSetAtlasSource : public TileSetSource {
GDCLASS(TileSetAtlasSource, TileSetSource);
-public:
+private:
struct TileAlternativesData {
Vector2i size_in_atlas = Vector2i(1, 1);
Vector2i texture_offset;
+
+ // Animation
+ int animation_columns = 0;
+ Vector2i animation_separation;
+ real_t animation_speed = 1.0;
+ LocalVector<real_t> animation_frames_durations;
+
+ // Alternatives
Map<int, TileData *> alternatives;
Vector<int> alternatives_ids;
int next_alternative_id = 1;
};
-private:
Ref<Texture2D> texture;
Vector2i margins;
Vector2i separation;
@@ -471,6 +478,9 @@ private:
void _compute_next_alternative_id(const Vector2i p_atlas_coords);
+ void _create_coords_mapping_cache(Vector2i p_atlas_coords);
+ void _clear_coords_mapping_cache(Vector2i p_atlas_coords);
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -513,18 +523,32 @@ public:
Vector2i get_texture_region_size() const;
// Base tiles.
- void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1)); // Create a tile if it does not exists, or add alternative tile if it does.
- void remove_tile(Vector2i p_atlas_coords); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
+ void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1));
+ void remove_tile(Vector2i p_atlas_coords);
virtual bool has_tile(Vector2i p_atlas_coords) const override;
- bool can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1)) const;
void move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1));
Vector2i get_tile_size_in_atlas(Vector2i p_atlas_coords) const;
virtual int get_tiles_count() const override;
virtual Vector2i get_tile_id(int p_index) const override;
+ bool has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile = INVALID_ATLAS_COORDS) const;
+
Vector2i get_tile_at_coords(Vector2i p_atlas_coords) const;
+ // Animation.
+ void set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns);
+ int get_tile_animation_columns(const Vector2i p_atlas_coords) const;
+ void set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation);
+ Vector2i get_tile_animation_separation(const Vector2i p_atlas_coords) const;
+ void set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed);
+ real_t get_tile_animation_speed(const Vector2i p_atlas_coords) const;
+ void set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count);
+ int get_tile_animation_frames_count(const Vector2i p_atlas_coords) const;
+ void set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration);
+ real_t get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const;
+ real_t get_tile_animation_total_duration(const Vector2i p_atlas_coords) const;
+
// Alternative tiles.
int create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override = -1);
void remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile);
@@ -542,7 +566,7 @@ public:
Vector2i get_atlas_grid_size() const;
bool has_tiles_outside_texture();
void clear_tiles_outside_texture();
- Rect2i get_tile_texture_region(Vector2i p_atlas_coords) const;
+ Rect2i get_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const;
Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const;
~TileSetAtlasSource();
diff --git a/scene/resources/world_margin_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp
index 3b43681528..39af92793f 100644
--- a/scene/resources/world_margin_shape_2d.cpp
+++ b/scene/resources/world_boundary_shape_2d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* world_margin_shape_2d.cpp */
+/* world_boundary_shape_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "world_margin_shape_2d.h"
+#include "world_boundary_shape_2d.h"
#include "core/math/geometry_2d.h"
#include "servers/physics_server_2d.h"
#include "servers/rendering_server.h"
-bool WorldMarginShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+bool WorldBoundaryShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
Vector2 point = get_distance() * get_normal();
Vector2 l[2][2] = { { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }, { point, point + get_normal() * 30 } };
@@ -48,7 +48,7 @@ bool WorldMarginShape2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
return false;
}
-void WorldMarginShape2D::_update_shape() {
+void WorldBoundaryShape2D::_update_shape() {
Array arr;
arr.push_back(normal);
arr.push_back(distance);
@@ -56,25 +56,25 @@ void WorldMarginShape2D::_update_shape() {
emit_changed();
}
-void WorldMarginShape2D::set_normal(const Vector2 &p_normal) {
+void WorldBoundaryShape2D::set_normal(const Vector2 &p_normal) {
normal = p_normal;
_update_shape();
}
-void WorldMarginShape2D::set_distance(real_t p_distance) {
+void WorldBoundaryShape2D::set_distance(real_t p_distance) {
distance = p_distance;
_update_shape();
}
-Vector2 WorldMarginShape2D::get_normal() const {
+Vector2 WorldBoundaryShape2D::get_normal() const {
return normal;
}
-real_t WorldMarginShape2D::get_distance() const {
+real_t WorldBoundaryShape2D::get_distance() const {
return distance;
}
-void WorldMarginShape2D::draw(const RID &p_to_rid, const Color &p_color) {
+void WorldBoundaryShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector2 point = get_distance() * get_normal();
Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 };
@@ -83,7 +83,7 @@ void WorldMarginShape2D::draw(const RID &p_to_rid, const Color &p_color) {
RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3);
}
-Rect2 WorldMarginShape2D::get_rect() const {
+Rect2 WorldBoundaryShape2D::get_rect() const {
Vector2 point = get_distance() * get_normal();
Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 };
@@ -96,22 +96,22 @@ Rect2 WorldMarginShape2D::get_rect() const {
return rect;
}
-real_t WorldMarginShape2D::get_enclosing_radius() const {
+real_t WorldBoundaryShape2D::get_enclosing_radius() const {
return distance;
}
-void WorldMarginShape2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_normal", "normal"), &WorldMarginShape2D::set_normal);
- ClassDB::bind_method(D_METHOD("get_normal"), &WorldMarginShape2D::get_normal);
+void WorldBoundaryShape2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_normal", "normal"), &WorldBoundaryShape2D::set_normal);
+ ClassDB::bind_method(D_METHOD("get_normal"), &WorldBoundaryShape2D::get_normal);
- ClassDB::bind_method(D_METHOD("set_distance", "distance"), &WorldMarginShape2D::set_distance);
- ClassDB::bind_method(D_METHOD("get_distance"), &WorldMarginShape2D::get_distance);
+ ClassDB::bind_method(D_METHOD("set_distance", "distance"), &WorldBoundaryShape2D::set_distance);
+ ClassDB::bind_method(D_METHOD("get_distance"), &WorldBoundaryShape2D::get_distance);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance"), "set_distance", "get_distance");
}
-WorldMarginShape2D::WorldMarginShape2D() :
- Shape2D(PhysicsServer2D::get_singleton()->world_margin_shape_create()) {
+WorldBoundaryShape2D::WorldBoundaryShape2D() :
+ Shape2D(PhysicsServer2D::get_singleton()->world_boundary_shape_create()) {
_update_shape();
}
diff --git a/scene/resources/world_margin_shape_2d.h b/scene/resources/world_boundary_shape_2d.h
index 3c1d593ffe..4cc60f5985 100644
--- a/scene/resources/world_margin_shape_2d.h
+++ b/scene/resources/world_boundary_shape_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* world_margin_shape_2d.h */
+/* world_boundary_shape_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WORLD_MARGIN_SHAPE_2D_H
-#define WORLD_MARGIN_SHAPE_2D_H
+#ifndef WORLD_BOUNDARY_SHAPE_2D_H
+#define WORLD_BOUNDARY_SHAPE_2D_H
#include "scene/resources/shape_2d.h"
-class WorldMarginShape2D : public Shape2D {
- GDCLASS(WorldMarginShape2D, Shape2D);
+class WorldBoundaryShape2D : public Shape2D {
+ GDCLASS(WorldBoundaryShape2D, Shape2D);
- // WorldMarginShape2D is often used for one-way platforms, where the normal pointing up makes sense.
+ // WorldBoundaryShape2D is often used for one-way platforms, where the normal pointing up makes sense.
Vector2 normal = Vector2(0, -1);
real_t distance = 0.0;
@@ -58,7 +58,7 @@ public:
virtual Rect2 get_rect() const override;
virtual real_t get_enclosing_radius() const override;
- WorldMarginShape2D();
+ WorldBoundaryShape2D();
};
-#endif // WORLD_MARGIN_SHAPE_2D_H
+#endif // WORLD_BOUNDARY_SHAPE_2D_H
diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_boundary_shape_3d.cpp
index 28d50e1921..8cde537164 100644
--- a/scene/resources/world_margin_shape_3d.cpp
+++ b/scene/resources/world_boundary_shape_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* world_margin_shape_3d.cpp */
+/* world_boundary_shape_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "world_margin_shape_3d.h"
+#include "world_boundary_shape_3d.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const {
+Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
Plane p = get_plane();
Vector<Vector3> points;
@@ -60,29 +60,29 @@ Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const {
return points;
}
-void WorldMarginShape3D::_update_shape() {
+void WorldBoundaryShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane);
Shape3D::_update_shape();
}
-void WorldMarginShape3D::set_plane(Plane p_plane) {
+void WorldBoundaryShape3D::set_plane(const Plane &p_plane) {
plane = p_plane;
_update_shape();
notify_change_to_owners();
}
-Plane WorldMarginShape3D::get_plane() const {
+const Plane &WorldBoundaryShape3D::get_plane() const {
return plane;
}
-void WorldMarginShape3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldMarginShape3D::set_plane);
- ClassDB::bind_method(D_METHOD("get_plane"), &WorldMarginShape3D::get_plane);
+void WorldBoundaryShape3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane);
+ ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane);
ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane");
}
-WorldMarginShape3D::WorldMarginShape3D() :
- Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_PLANE)) {
+WorldBoundaryShape3D::WorldBoundaryShape3D() :
+ Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY)) {
set_plane(Plane(0, 1, 0, 0));
}
diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_boundary_shape_3d.h
index 00417c4408..853f555ebc 100644
--- a/scene/resources/world_margin_shape_3d.h
+++ b/scene/resources/world_boundary_shape_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* world_margin_shape_3d.h */
+/* world_boundary_shape_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WORLD_MARGIN_SHAPE_3D_H
-#define WORLD_MARGIN_SHAPE_3D_H
+#ifndef WORLD_BOUNDARY_SHAPE_3D_H
+#define WORLD_BOUNDARY_SHAPE_3D_H
#include "scene/resources/shape_3d.h"
-class WorldMarginShape3D : public Shape3D {
- GDCLASS(WorldMarginShape3D, Shape3D);
+class WorldBoundaryShape3D : public Shape3D {
+ GDCLASS(WorldBoundaryShape3D, Shape3D);
Plane plane;
protected:
@@ -42,8 +42,8 @@ protected:
virtual void _update_shape() override;
public:
- void set_plane(Plane p_plane);
- Plane get_plane() const;
+ void set_plane(const Plane &p_plane);
+ const Plane &get_plane() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override {
@@ -51,6 +51,6 @@ public:
return 0;
}
- WorldMarginShape3D();
+ WorldBoundaryShape3D();
};
-#endif // WORLD_MARGIN_SHAPE_H
+#endif // WORLD_BOUNDARY_SHAPE_H
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 5d89d295c2..b283749ffa 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -91,9 +91,6 @@ SceneStringNames::SceneStringNames() {
update = StaticCString::create("update");
updated = StaticCString::create("updated");
- _get_gizmo_geometry = StaticCString::create("_get_gizmo_geometry");
- _can_gizmo_scale = StaticCString::create("_can_gizmo_scale");
-
_physics_process = StaticCString::create("_physics_process");
_process = StaticCString::create("_process");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 01f427ecd1..2923351eab 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -111,9 +111,6 @@ public:
StringName _body_inout;
StringName _area_inout;
- StringName _get_gizmo_geometry;
- StringName _can_gizmo_scale;
-
StringName _physics_process;
StringName _process;
StringName _enter_world;