ソースを参照

Merge pull request #18764 from AndreaCatania/rag

Improved API to active / deactive ragdoll
Juan Linietsky 7 年 前
コミット
dc7060973c
3 ファイル変更85 行追加25 行削除
  1. 3 6
      scene/3d/physics_body.cpp
  2. 77 17
      scene/3d/skeleton.cpp
  3. 5 2
      scene/3d/skeleton.h

+ 3 - 6
scene/3d/physics_body.cpp

@@ -1825,6 +1825,7 @@ void PhysicalBone::_notification(int p_what) {
 			parent_skeleton = find_skeleton_parent(get_parent());
 			update_bone_id();
 			reset_to_rest_position();
+			_reset_physics_simulation_state();
 			break;
 		case NOTIFICATION_EXIT_TREE:
 			if (parent_skeleton) {
@@ -1886,10 +1887,8 @@ void PhysicalBone::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset);
 	ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset);
 
-	ClassDB::bind_method(D_METHOD("set_static_body", "simulate"), &PhysicalBone::set_static_body);
 	ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body);
 
-	ClassDB::bind_method(D_METHOD("set_simulate_physics", "simulate"), &PhysicalBone::set_simulate_physics);
 	ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
 
 	ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
@@ -1913,9 +1912,7 @@ void PhysicalBone::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
 
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simulate_physics"), "set_simulate_physics", "get_simulate_physics");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "static_body"), "set_static_body", "is_static_body");
 
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
@@ -2255,8 +2252,8 @@ PhysicalBone::PhysicalBone() :
 		joint_data(NULL),
 		static_body(false),
 		simulate_physics(false),
-		_internal_static_body(!static_body),
-		_internal_simulate_physics(simulate_physics),
+		_internal_static_body(false),
+		_internal_simulate_physics(false),
 		bone_id(-1),
 		parent_skeleton(NULL),
 		bone_name(""),

+ 77 - 17
scene/3d/skeleton.cpp

@@ -330,7 +330,7 @@ void Skeleton::add_bone(const String &p_name) {
 	_make_dirty();
 	update_gizmo();
 }
-int Skeleton::find_bone(String p_name) const {
+int Skeleton::find_bone(const String &p_name) const {
 
 	for (int i = 0; i < bones.size(); i++) {
 
@@ -347,6 +347,19 @@ String Skeleton::get_bone_name(int p_bone) const {
 	return bones[p_bone].name;
 }
 
+bool Skeleton::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
+
+	int parent_of_bone = get_bone_parent(p_bone);
+
+	if (-1 == parent_of_bone)
+		return false;
+
+	if (parent_of_bone == p_parent_bone_id)
+		return true;
+
+	return is_bone_parent_of(parent_of_bone, p_parent_bone_id);
+}
+
 int Skeleton::get_bone_count() const {
 
 	return bones.size();
@@ -534,18 +547,6 @@ void Skeleton::localize_rests() {
 	}
 }
 
-void _notify_physical_bones_simulation(bool start, Node *p_node) {
-
-	for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
-		_notify_physical_bones_simulation(start, p_node->get_child(i));
-	}
-
-	PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
-	if (pb) {
-		pb->set_simulate_physics(start);
-	}
-}
-
 void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
 	ERR_FAIL_INDEX(p_bone, bones.size());
 	ERR_FAIL_COND(bones[p_bone].physical_bone);
@@ -603,8 +604,67 @@ void Skeleton::_rebuild_physical_bones_cache() {
 	}
 }
 
-void Skeleton::physical_bones_simulation(bool start) {
-	_notify_physical_bones_simulation(start, this);
+void _pb_stop_simulation(Node *p_node) {
+
+	for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+		_pb_stop_simulation(p_node->get_child(i));
+	}
+
+	PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+	if (pb) {
+		pb->set_simulate_physics(false);
+		pb->set_static_body(false);
+	}
+}
+
+void Skeleton::physical_bones_stop_simulation() {
+	_pb_stop_simulation(this);
+}
+
+void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
+
+	for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+		_pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones);
+	}
+
+	PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+	if (pb) {
+		bool sim = false;
+		for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+			if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+				sim = true;
+				break;
+			}
+		}
+
+		pb->set_simulate_physics(true);
+		if (sim) {
+			pb->set_static_body(false);
+		} else {
+			pb->set_static_body(true);
+		}
+	}
+}
+
+void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
+
+	Vector<int> sim_bones;
+	if (p_bones.size() <= 0) {
+		sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
+	} else {
+		sim_bones.resize(p_bones.size());
+		int c = 0;
+		for (int i = sim_bones.size() - 1; 0 <= i; --i) {
+			if (Variant::STRING == p_bones.get(i).get_type()) {
+				int bone_id = find_bone(p_bones.get(i));
+				if (bone_id != -1)
+					sim_bones[c++] = bone_id;
+			}
+		}
+		sim_bones.resize(c);
+	}
+
+	_pb_start_simulation(this, this, sim_bones);
 }
 
 void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
@@ -667,7 +727,8 @@ void Skeleton::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
 
-	ClassDB::bind_method(D_METHOD("physical_bones_simulation", "start"), &Skeleton::physical_bones_simulation);
+	ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
+	ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array()));
 	ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception);
 	ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
 
@@ -683,6 +744,5 @@ Skeleton::Skeleton() {
 }
 
 Skeleton::~Skeleton() {
-
 	VisualServer::get_singleton()->free(skeleton);
 }

+ 5 - 2
scene/3d/skeleton.h

@@ -120,9 +120,11 @@ public:
 
 	// skeleton creation api
 	void add_bone(const String &p_name);
-	int find_bone(String p_name) const;
+	int find_bone(const String &p_name) const;
 	String get_bone_name(int p_bone) const;
 
+	bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
+
 	void set_bone_parent(int p_bone, int p_parent);
 	int get_bone_parent(int p_bone) const;
 
@@ -176,7 +178,8 @@ private:
 	void _rebuild_physical_bones_cache();
 
 public:
-	void physical_bones_simulation(bool start);
+	void physical_bones_stop_simulation();
+	void physical_bones_start_simulation_on(const Array &p_bones);
 	void physical_bones_add_collision_exception(RID p_exception);
 	void physical_bones_remove_collision_exception(RID p_exception);