/// <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) { 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? transform: connectTo.transform; 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; } UpdateHierarchies(); CheckMassVariation(100f, true); }
// Add all child indexes to the indexes array recursively private void AddToChildrenRecursive(ConfigurableJoint joint, ref int[] indexes, ref bool[] childFlags) { if (joint == null) return; int muscleIndex = GetMuscleIndexLowLevel(joint); if (muscleIndex == -1) return; Array.Resize(ref indexes, indexes.Length + 1); indexes[indexes.Length - 1] = muscleIndex; childFlags[muscleIndex] = true; for (int i = 0; i < muscles.Length; i++) { if (i != muscleIndex && muscles[i].joint.connectedBody == joint.GetComponent<Rigidbody>()) { AddToChildrenRecursive(muscles[i].joint, ref indexes, ref childFlags); } } }