private void ReconnectMuscle(Muscle m) { m.state.isDisconnected = false; if (activeState != State.Frozen && !m.isPropMuscle) { m.target.position = m.targetAnimatedPosition; m.target.rotation = m.targetAnimatedWorldRotation; } if (m != muscles[0]) { m.joint.xMotion = ConfigurableJointMotion.Locked; m.joint.yMotion = ConfigurableJointMotion.Locked; m.joint.zMotion = ConfigurableJointMotion.Locked; if (!hierarchyIsFlat && m.joint.connectedBody != null) { m.transform.parent = m.joint.connectedBody.transform; } } bool disable = false; if (m.joint.connectedBody != null && !m.joint.connectedBody.gameObject.activeInHierarchy) { disable = true; } if (m.joint.connectedBody == null) { if (activeMode == Mode.Disabled || activeState == State.Frozen) { disable = true; } } if (disable) { m.joint.gameObject.SetActive(false); } else { if (!m.joint.gameObject.activeInHierarchy || m.state.resetFlag) { m.Reset(); m.joint.gameObject.SetActive(true); } else { if (activeState != State.Frozen) { m.MoveToTarget(); } } } if (activeMode == Mode.Kinematic) { m.SetKinematic(true); } if (activeState == State.Dead) { m.ResetTargetLocalPosition(); m.SetMuscleRotation(muscleWeight * stateSettings.deadMuscleWeight, muscleSpring, muscleDamper + stateSettings.deadMuscleDamper); } m.state.resetFlag = false; m.ClearVelocities(); m.state.pinWeightMlp = 1; m.state.muscleWeightMlp = 1; m.state.muscleDamperMlp = 1; m.state.maxForceMlp = 1; m.state.mappingWeightMlp = 1f; UpdateInternalCollisions(m); m.IgnoreAngularLimits(!angularLimits); foreach (BehaviourBase b in behaviours) { b.OnMuscleReconnected(m); } if (OnMuscleReconnected != null) { OnMuscleReconnected(m); } }
/// <summary> /// NB! Make sure to call this from FixedUpdate! /// Creates a new muscle for the specified "joint" and targets it to the "target". The joint will be connected to the specified "connectTo" Muscle. /// Note that the joint will be binded to it's current position and rotation relative to the "connectTo", so make sure the added object is positioned correctly when calling this. /// This method allocates memory, avoid using it each frame. /// </summary> public void AddMuscle(ConfigurableJoint joint, Transform target, Rigidbody connectTo, Transform targetParent, Muscle.Props muscleProps = null, bool forceTreeHierarchy = false, bool forceLayers = true) { if (!CheckIfInitiated()) { return; } if (!initiated) { Debug.LogWarning("PuppetMaster has not been initiated.", transform); return; } if (ContainsJoint(joint)) { Debug.LogWarning("Joint " + joint.name + " is already used by a Muscle", transform); return; } if (target == null) { Debug.LogWarning("AddMuscle was called with a null 'target' reference.", transform); return; } if (connectTo == joint.GetComponent <Rigidbody>()) { Debug.LogWarning("ConnectTo is the joint's own Rigidbody, can not add muscle.", transform); return; } if (!isActive) { Debug.LogWarning("Adding muscles to inactive PuppetMasters is not currently supported.", transform); return; } if (muscleProps == null) { muscleProps = new Muscle.Props(); } Muscle muscle = new Muscle(); muscle.props = muscleProps; muscle.joint = joint; muscle.target = target; muscle.joint.transform.parent = (hierarchyIsFlat || connectTo == null) && !forceTreeHierarchy? transform: connectTo.transform; if (forceLayers) { joint.gameObject.layer = gameObject.layer; //@todo what if collider is on a child gameobject? target.gameObject.layer = targetRoot.gameObject.layer; } if (connectTo != null) { muscle.target.parent = targetParent; Vector3 relativePosition = GetMuscle(connectTo).transform.InverseTransformPoint(muscle.target.position); Quaternion relativeRotation = Quaternion.Inverse(GetMuscle(connectTo).transform.rotation) * muscle.target.rotation; joint.transform.position = connectTo.transform.TransformPoint(relativePosition); joint.transform.rotation = connectTo.transform.rotation * relativeRotation; joint.connectedBody = connectTo; } muscle.Initiate(muscles); if (connectTo != null) { muscle.rigidbody.velocity = connectTo.velocity; muscle.rigidbody.angularVelocity = connectTo.angularVelocity; } // Ignore internal collisions if (!internalCollisions) { for (int i = 0; i < muscles.Length; i++) { muscle.IgnoreCollisions(muscles[i], true); } } Array.Resize(ref muscles, muscles.Length + 1); muscles[muscles.Length - 1] = muscle; // Update angular limit ignoring muscle.IgnoreAngularLimits(!angularLimits); if (behaviours.Length > 0) { muscle.broadcaster = muscle.joint.gameObject.AddComponent <MuscleCollisionBroadcaster>(); muscle.broadcaster.puppetMaster = this; muscle.broadcaster.muscleIndex = muscles.Length - 1; } muscle.jointBreakBroadcaster = muscle.joint.gameObject.AddComponent <JointBreakBroadcaster>(); muscle.jointBreakBroadcaster.puppetMaster = this; muscle.jointBreakBroadcaster.muscleIndex = muscles.Length - 1; UpdateHierarchies(); CheckMassVariation(100f, true); foreach (BehaviourBase b in behaviours) { b.OnMuscleAdded(muscle); } }
private void DisconnectMuscle(Muscle m, bool sever, bool deactivate) { m.state.pinWeightMlp = 0f; m.state.muscleWeightMlp = 0f; m.state.muscleDamperAdd = 0f; m.state.muscleDamperMlp = 0f; m.state.mappingWeightMlp = 0f; m.state.maxForceMlp = 0f; m.state.immunity = 0f; m.state.impulseMlp = 1f; if (sever) { m.joint.xMotion = ConfigurableJointMotion.Free; m.joint.yMotion = ConfigurableJointMotion.Free; m.joint.zMotion = ConfigurableJointMotion.Free; m.IgnoreAngularLimits(true); if (!hierarchyIsFlat) { m.joint.transform.parent = transform; } } else { m.IgnoreAngularLimits(false); } bool applyMappedVelocity = !m.joint.gameObject.activeInHierarchy || m.rigidbody.isKinematic; if (activeState == State.Frozen) { applyMappedVelocity = false; } // In case disconnecting in disabled mode if (!m.joint.gameObject.activeInHierarchy && !deactivate) { m.MoveToTarget(); m.joint.gameObject.SetActive(true); } m.SetKinematic(false); JointDrive slerpDrive = new JointDrive(); slerpDrive.positionSpring = 0f; slerpDrive.maximumForce = 0f; slerpDrive.positionDamper = 0f; m.joint.slerpDrive = slerpDrive; // Enable internal collisions with the disconnected muscle if (!deactivate) { for (int i = 0; i < muscles.Length; i++) { if (muscles[i] != m && !muscles[i].state.isDisconnected) { foreach (Collider c1 in m.colliders) { foreach (Collider c2 in muscles[i].colliders) { if (c1.enabled && c2.enabled) { Physics.IgnoreCollision(c1, c2, false); } } } } } if (applyMappedVelocity) { m.rigidbody.velocity = m.mappedVelocity; m.rigidbody.angularVelocity = m.mappedAngularVelocity; } } else { m.joint.gameObject.SetActive(false); } if (m.isPropMuscle) { var propMuscle = m.joint.GetComponent <PropMuscle>(); if (propMuscle.activeProp != null) { propMuscle.currentProp = null; } } m.state.isDisconnected = true; foreach (BehaviourBase b in behaviours) { b.OnMuscleDisconnected(m); } if (OnMuscleDisconnected != null) { OnMuscleDisconnected(m); } }