/// <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); } }
/// <summary> /// Adds a PropMuscle to the puppet at runtime. If Vector3.zero passed for additionalPinOffset, additional pin will not be added. /// </summary> public bool AddPropMuscle(ConfigurableJoint addPropMuscleTo, Vector3 position, Quaternion rotation, Vector3 additionalPinOffset, Transform targetParent = null, PuppetMasterProp initiateWithProp = null) { if (!initiated) { Debug.LogError("Can not add Prop Muscle to PuppetMaster that has not been initiated! Please use Start() instead of Awake() or PuppetMaster.OnPostInitiate delegate to call AddPropMuscle.", transform); return(false); } if (addPropMuscleTo != null) { bool isFlat = HierarchyIsFlat(); var addToMuscle = GetMuscle(addPropMuscleTo); if (addToMuscle != null) { GameObject go = new GameObject("Prop Muscle " + addPropMuscleTo.name); go.layer = addPropMuscleTo.gameObject.layer; go.transform.parent = isFlat ? transform : addPropMuscleTo.transform; go.transform.position = position; go.transform.rotation = rotation; go.AddComponent <Rigidbody>(); GameObject target = new GameObject("Prop Muscle Target " + addPropMuscleTo.name); target.gameObject.layer = addToMuscle.target.gameObject.layer; target.transform.parent = targetParent != null? targetParent: addToMuscle.target; target.transform.position = go.transform.position; target.transform.rotation = go.transform.rotation; ConfigurableJoint joint = go.AddComponent <ConfigurableJoint>(); joint.xMotion = ConfigurableJointMotion.Locked; joint.yMotion = ConfigurableJointMotion.Locked; joint.zMotion = ConfigurableJointMotion.Locked; joint.angularXMotion = ConfigurableJointMotion.Locked; joint.angularYMotion = ConfigurableJointMotion.Locked; joint.angularZMotion = ConfigurableJointMotion.Locked; Muscle.Props props = new Muscle.Props(); props.group = Muscle.Group.Prop; AddMuscle(joint, target.transform, addPropMuscleTo.GetComponent <Rigidbody>(), targetParent != null ? targetParent : addToMuscle.target, props, false, true); muscles[muscles.Length - 1].isPropMuscle = true; var propMuscle = go.AddComponent <PropMuscle>(); propMuscle.puppetMaster = this; propMuscle.additionalPinOffset = additionalPinOffset; propMuscle.currentProp = initiateWithProp; if (additionalPinOffset != Vector3.zero) { propMuscle.AddAdditionalPin(); } Array.Resize(ref propMuscles, propMuscles.Length + 1); propMuscles[propMuscles.Length - 1] = propMuscle; propMuscle.OnInitiate(); return(true); } else { Debug.LogError("Can't add Prop Muscle to a ConfigurableJoint that is not in the list of PuppetMaster.muscles.", transform); return(false); } } else { Debug.LogError("Please assign the ConfigurableJoint of the muscle you wish to add the Prop Muscle to.", transform); return(false); } }