Added feature to move physical bones with skeleton when not simulating physics
This commit is contained in:
parent
343b29a651
commit
374432d074
4 changed files with 100 additions and 93 deletions
|
@ -1562,6 +1562,24 @@ void PhysicalBone::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse)
|
|||
PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
|
||||
}
|
||||
|
||||
void PhysicalBone::reset_physics_simulation_state() {
|
||||
if (simulate_physics) {
|
||||
_start_physics_simulation();
|
||||
} else {
|
||||
_stop_physics_simulation();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalBone::reset_to_rest_position() {
|
||||
if (parent_skeleton) {
|
||||
if (-1 == bone_id) {
|
||||
set_global_transform(parent_skeleton->get_global_transform() * body_offset);
|
||||
} else {
|
||||
set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
|
||||
if (JointData::_set(p_name, p_value, j)) {
|
||||
return true;
|
||||
|
@ -2167,7 +2185,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();
|
||||
reset_physics_simulation_state();
|
||||
if (!joint.is_valid() && joint_data) {
|
||||
_reload_joint();
|
||||
}
|
||||
|
@ -2238,8 +2256,6 @@ 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("is_static_body"), &PhysicalBone::is_static_body);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
|
||||
|
@ -2508,26 +2524,13 @@ const Transform &PhysicalBone::get_joint_offset() const {
|
|||
return joint_offset;
|
||||
}
|
||||
|
||||
void PhysicalBone::set_static_body(bool p_static) {
|
||||
|
||||
static_body = p_static;
|
||||
|
||||
set_as_toplevel(!static_body);
|
||||
|
||||
_reset_physics_simulation_state();
|
||||
}
|
||||
|
||||
bool PhysicalBone::is_static_body() {
|
||||
return static_body;
|
||||
}
|
||||
|
||||
void PhysicalBone::set_simulate_physics(bool p_simulate) {
|
||||
if (simulate_physics == p_simulate) {
|
||||
return;
|
||||
}
|
||||
|
||||
simulate_physics = p_simulate;
|
||||
_reset_physics_simulation_state();
|
||||
reset_physics_simulation_state();
|
||||
}
|
||||
|
||||
bool PhysicalBone::get_simulate_physics() {
|
||||
|
@ -2535,7 +2538,7 @@ bool PhysicalBone::get_simulate_physics() {
|
|||
}
|
||||
|
||||
bool PhysicalBone::is_simulating_physics() {
|
||||
return _internal_simulate_physics && !_internal_static_body;
|
||||
return _internal_simulate_physics;
|
||||
}
|
||||
|
||||
void PhysicalBone::set_bone_name(const String &p_name) {
|
||||
|
@ -2618,8 +2621,6 @@ PhysicalBone::PhysicalBone() :
|
|||
#endif
|
||||
joint_data(NULL),
|
||||
parent_skeleton(NULL),
|
||||
static_body(false),
|
||||
_internal_static_body(false),
|
||||
simulate_physics(false),
|
||||
_internal_simulate_physics(false),
|
||||
bone_id(-1),
|
||||
|
@ -2629,8 +2630,7 @@ PhysicalBone::PhysicalBone() :
|
|||
friction(1),
|
||||
gravity_scale(1) {
|
||||
|
||||
set_static_body(static_body);
|
||||
_reset_physics_simulation_state();
|
||||
reset_physics_simulation_state();
|
||||
}
|
||||
|
||||
PhysicalBone::~PhysicalBone() {
|
||||
|
@ -2657,8 +2657,7 @@ void PhysicalBone::update_bone_id() {
|
|||
parent_skeleton->bind_physical_bone_to_bone(bone_id, this);
|
||||
|
||||
_fix_joint_offset();
|
||||
_internal_static_body = !static_body; // Force staticness reset
|
||||
_reset_staticness_state();
|
||||
reset_physics_simulation_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2680,49 +2679,6 @@ void PhysicalBone::update_offset() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void PhysicalBone::reset_to_rest_position() {
|
||||
if (parent_skeleton) {
|
||||
if (-1 == bone_id) {
|
||||
set_global_transform(parent_skeleton->get_global_transform() * body_offset);
|
||||
} else {
|
||||
set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalBone::_reset_physics_simulation_state() {
|
||||
if (simulate_physics && !static_body) {
|
||||
_start_physics_simulation();
|
||||
} else {
|
||||
_stop_physics_simulation();
|
||||
}
|
||||
|
||||
_reset_staticness_state();
|
||||
}
|
||||
|
||||
void PhysicalBone::_reset_staticness_state() {
|
||||
|
||||
if (parent_skeleton && -1 != bone_id) {
|
||||
if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary
|
||||
|
||||
if (_internal_static_body) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent_skeleton->bind_child_node_to_bone(bone_id, this);
|
||||
_internal_static_body = true;
|
||||
} else {
|
||||
|
||||
if (!_internal_static_body) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent_skeleton->unbind_child_node_from_bone(bone_id, this);
|
||||
_internal_static_body = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalBone::_start_physics_simulation() {
|
||||
if (_internal_simulate_physics || !parent_skeleton) {
|
||||
return;
|
||||
|
@ -2732,17 +2688,27 @@ void PhysicalBone::_start_physics_simulation() {
|
|||
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
|
||||
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
|
||||
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
|
||||
set_as_toplevel(true);
|
||||
_internal_simulate_physics = true;
|
||||
}
|
||||
|
||||
void PhysicalBone::_stop_physics_simulation() {
|
||||
if (!_internal_simulate_physics || !parent_skeleton) {
|
||||
if (!parent_skeleton) {
|
||||
return;
|
||||
}
|
||||
if (parent_skeleton->get_animate_physical_bones()) {
|
||||
PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_KINEMATIC);
|
||||
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
|
||||
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
|
||||
} else {
|
||||
PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC);
|
||||
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0);
|
||||
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0);
|
||||
}
|
||||
if (_internal_simulate_physics) {
|
||||
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
|
||||
parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
|
||||
set_as_toplevel(false);
|
||||
_internal_simulate_physics = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -562,8 +562,6 @@ private:
|
|||
Skeleton *parent_skeleton;
|
||||
Transform body_offset;
|
||||
Transform body_offset_inverse;
|
||||
bool static_body;
|
||||
bool _internal_static_body;
|
||||
bool simulate_physics;
|
||||
bool _internal_simulate_physics;
|
||||
int bone_id;
|
||||
|
@ -613,9 +611,6 @@ public:
|
|||
void set_body_offset(const Transform &p_offset);
|
||||
const Transform &get_body_offset() const;
|
||||
|
||||
void set_static_body(bool p_static);
|
||||
bool is_static_body();
|
||||
|
||||
void set_simulate_physics(bool p_simulate);
|
||||
bool get_simulate_physics();
|
||||
bool is_simulating_physics();
|
||||
|
@ -641,16 +636,15 @@ public:
|
|||
void apply_central_impulse(const Vector3 &p_impulse);
|
||||
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
|
||||
|
||||
void reset_physics_simulation_state();
|
||||
void reset_to_rest_position();
|
||||
|
||||
PhysicalBone();
|
||||
~PhysicalBone();
|
||||
|
||||
private:
|
||||
void update_bone_id();
|
||||
void update_offset();
|
||||
void reset_to_rest_position();
|
||||
|
||||
void _reset_physics_simulation_state();
|
||||
void _reset_staticness_state();
|
||||
|
||||
void _start_physics_simulation();
|
||||
void _stop_physics_simulation();
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/message_queue.h"
|
||||
|
||||
#include "core/engine.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "scene/3d/physics_body.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
@ -332,6 +333,27 @@ void Skeleton::_notification(int p_what) {
|
|||
|
||||
dirty = false;
|
||||
} break;
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||
// This is active only if the skeleton animates the physical bones
|
||||
// and the state of the bone is not active.
|
||||
if (animate_physical_bones) {
|
||||
for (int i = 0; i < bones.size(); i += 1) {
|
||||
if (bones[i].physical_bone) {
|
||||
if (bones[i].physical_bone->is_simulating_physics() == false) {
|
||||
bones[i].physical_bone->reset_to_rest_position();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_READY: {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
set_physics_process_internal(true);
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,6 +606,27 @@ void Skeleton::localize_rests() {
|
|||
|
||||
#ifndef _3D_DISABLED
|
||||
|
||||
void Skeleton::set_animate_physical_bones(bool p_animate) {
|
||||
animate_physical_bones = p_animate;
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() == false) {
|
||||
bool sim = false;
|
||||
for (int i = 0; i < bones.size(); i += 1) {
|
||||
if (bones[i].physical_bone) {
|
||||
bones[i].physical_bone->reset_physics_simulation_state();
|
||||
if (bones[i].physical_bone->is_simulating_physics()) {
|
||||
sim = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
set_physics_process_internal(sim == false && p_animate);
|
||||
}
|
||||
}
|
||||
|
||||
bool Skeleton::get_animate_physical_bones() const {
|
||||
return animate_physical_bones;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -653,12 +696,14 @@ void _pb_stop_simulation(Node *p_node) {
|
|||
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);
|
||||
if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) {
|
||||
set_physics_process_internal(true);
|
||||
}
|
||||
}
|
||||
|
||||
void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
|
||||
|
@ -669,24 +714,17 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector
|
|||
|
||||
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;
|
||||
pb->set_simulate_physics(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) {
|
||||
set_physics_process_internal(false);
|
||||
|
||||
Vector<int> sim_bones;
|
||||
if (p_bones.size() <= 0) {
|
||||
|
@ -836,11 +874,15 @@ void Skeleton::_bind_methods() {
|
|||
|
||||
#ifndef _3D_DISABLED
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton::set_animate_physical_bones);
|
||||
ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::get_animate_physical_bones);
|
||||
|
||||
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);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
|
||||
#endif // _3D_DISABLED
|
||||
|
||||
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
|
||||
|
@ -848,6 +890,7 @@ void Skeleton::_bind_methods() {
|
|||
|
||||
Skeleton::Skeleton() {
|
||||
|
||||
animate_physical_bones = true;
|
||||
dirty = false;
|
||||
process_order_dirty = true;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
bool animate_physical_bones;
|
||||
Vector<Bone> bones;
|
||||
Vector<int> process_order;
|
||||
bool process_order_dirty;
|
||||
|
@ -199,6 +200,9 @@ public:
|
|||
#ifndef _3D_DISABLED
|
||||
// Physical bone API
|
||||
|
||||
void set_animate_physical_bones(bool p_animate);
|
||||
bool get_animate_physical_bones() const;
|
||||
|
||||
void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
|
||||
void unbind_physical_bone_from_bone(int p_bone);
|
||||
|
||||
|
|
Loading…
Reference in a new issue