using UnityEngine; using System.Collections; namespace RootMotion.Dynamics { // Handles damaging the puppet via collisions and hits. public partial class BehaviourPuppet : BehaviourBase { private MuscleCollisionBroadcaster broadcaster; /// /// Knock out this puppet. /// public void Unpin() { SetState(State.Unpinned); } // When a muscle is hit (through MuscleCollisionBroadcaster.Hit(...)) protected override void OnMuscleHitBehaviour(MuscleHit hit) { // Should we activate the puppet? if (masterProps.normalMode == NormalMode.Kinematic) puppetMaster.mode = PuppetMaster.Mode.Active; // Unpin the muscle (and other muscles) and add force UnPin(hit.muscleIndex, hit.unPin); // Add force puppetMaster.muscles[hit.muscleIndex].SetKinematic(false); puppetMaster.muscles[hit.muscleIndex].rigidbody.AddForceAtPosition(hit.force, hit.position); } // When a muscle collides with something (called by the MuscleCollisionBroadcaster component on the muscle). protected override void OnMuscleCollisionBehaviour(MuscleCollision m) { if (OnCollision != null) OnCollision(m); // All the conditions for ignoring this if (!enabled) return; if (state == State.Unpinned) return; if (collisions > maxCollisions) return; if (!LayerMaskExtensions.Contains(collisionLayers, m.collision.collider.gameObject.layer)) return; if (LayerMaskExtensions.Contains(groundLayers, m.collision.collider.gameObject.layer)) { if (state == State.GetUp) return; // Do not damage if contact with ground layers and in getup state if (puppetMaster.muscles[m.muscleIndex].props.group == Muscle.Group.Foot) return; // Do not damage if feet in contact with ground layers } if (masterProps.normalMode == NormalMode.Kinematic && !puppetMaster.isActive && !masterProps.activateOnStaticCollisions && m.collision.gameObject.isStatic) return; // Activate on Kinematic-Kinematic pair if (puppetMaster.muscles[m.muscleIndex].rigidbody.isKinematic && m.collision.collider.attachedRigidbody != null && m.collision.collider.attachedRigidbody.isKinematic) { if (masterProps.normalMode == NormalMode.Kinematic && puppetMaster.mode == PuppetMaster.Mode.Kinematic) puppetMaster.mode = PuppetMaster.Mode.Active; } else { // Get the collision impulse on the muscle float cT = collisionThreshold; float impulse = GetImpulse(m, ref cT); float minImpulseMlp = PuppetMasterSettings.instance != null ? (1f + PuppetMasterSettings.instance.currentlyActivePuppets * PuppetMasterSettings.instance.activePuppetCollisionThresholdMlp) : 1f; float minImpulse = cT * minImpulseMlp; if (impulse <= minImpulse) return; collisions++; // Try to find out if it collided with another puppet's muscle if (m.collision.collider.attachedRigidbody != null) { broadcaster = m.collision.collider.attachedRigidbody.GetComponent(); if (broadcaster != null) { if (broadcaster.muscleIndex < broadcaster.puppetMaster.muscles.Length) { // Multiply impulse (if the other muscle has been boosted) impulse *= broadcaster.puppetMaster.muscles[broadcaster.muscleIndex].state.impulseMlp; //float stayF = m.isStay? 0.05f: 0.1f; //broadcaster.puppetMaster.muscles[broadcaster.muscleIndex].offset -= m.collision.impulse * Time.deltaTime * stayF; } } } // DO not move this up, the impulse value will be wrong. // Let other scripts know about the collision (even the ones below collision threshold) if (OnCollisionImpulse != null) OnCollisionImpulse(m, impulse); // Should we activate the puppet? if (Activate(m.collision, impulse)) puppetMaster.mode = PuppetMaster.Mode.Active; // Unpin the muscle (and other muscles) UnPin(m.muscleIndex, impulse); } } // Calculating the impulse magnitude from a collision private float GetImpulse(MuscleCollision m, ref float layerThreshold) { float i = m.collision.impulse.sqrMagnitude; i /= puppetMaster.muscles [m.muscleIndex].rigidbody.mass; i *= 0.3f; // Coeficient for evening out for pre-0.3 versions // Collision resistance multipliers foreach (CollisionResistanceMultiplier crm in collisionResistanceMultipliers) { if (LayerMaskExtensions.Contains(crm.layers, m.collision.collider.gameObject.layer)) { if (crm.multiplier <= 0f) i = Mathf.Infinity; else i /= crm.multiplier; layerThreshold = crm.collisionThreshold; break; } } return i; } // Unpin a muscle and other muscles linked to it public void UnPin(int muscleIndex, float unpin) { if (muscleIndex >= puppetMaster.muscles.Length) return; BehaviourPuppet.MuscleProps props = GetProps(puppetMaster.muscles[muscleIndex].props.group); for (int i = 0; i < puppetMaster.muscles.Length; i++) { UnPinMuscle(i, unpin * GetFalloff(i, muscleIndex, props.unpinParents, props.unpinChildren, props.unpinGroup)); } hasCollidedSinceGetUp = true; lastCollisionTime = Time.time; } // Unpin a specific muscle according to its collision resistance, immunity and other values private void UnPinMuscle(int muscleIndex, float unpin) { // All the conditions to ignore this if (unpin <= 0f) return; if (puppetMaster.muscles[muscleIndex].state.immunity >= 1f) return; // Find the group properties BehaviourPuppet.MuscleProps props = GetProps(puppetMaster.muscles[muscleIndex].props.group); // Making the puppet more resistant to collisions while getting up float stateF = 1f; if (state == State.GetUp) stateF = Mathf.Lerp(getUpCollisionResistanceMlp, 1f, puppetMaster.muscles[muscleIndex].state.pinWeightMlp); // Applying collision resistance float cR = collisionResistance.mode == Weight.Mode.Float? collisionResistance.floatValue: collisionResistance.GetValue(puppetMaster.muscles[muscleIndex].targetVelocity.magnitude); float damage = unpin / (props.collisionResistance * cR * stateF); damage *= 1f - puppetMaster.muscles[muscleIndex].state.immunity; // Finally apply the damage //puppetMaster.muscles[muscleIndex].state.pinWeightMlp -= damage; if (!puppetMaster.muscles[muscleIndex].state.isDisconnected) { puppetMaster.muscles[muscleIndex].state.pinWeightMlp = Mathf.Max(puppetMaster.muscles[muscleIndex].state.pinWeightMlp - damage, props.minPinWeight); } } private bool Activate(Collision collision, float impulse) { if (masterProps.normalMode != NormalMode.Kinematic) return false; if (puppetMaster.mode != PuppetMaster.Mode.Kinematic) return false; if (impulse < masterProps.activateOnImpulse) return false; if (collision.gameObject.isStatic) { return masterProps.activateOnStaticCollisions; } return true; } } }