using UnityEngine; using System.Collections; namespace RootMotion.Dynamics { /// /// Dynamic pin, drag and mapping weight control based on collisions with objects. /// public class PuppetControllerLite : MonoBehaviour, ICollisionEventListener { [System.Serializable] public class Group { public string name; [Tooltip("The muscle groups to apply this pinWeightMlp and muscleWeightMlp to.")] public int[] indices = new int[0]; [Range(0f, 1f)] public float pinWeightMlp = 0.5f; [Range(0f, 1f)] public float muscleWeightMlp = 0.5f; [Tooltip("When the puppet is touched, sets muscle Rigidbody drag to this value to reduce the rubber chicken effect.")] public float drag = 2f; [Tooltip("The time of blending in this script's effects when the puppet is touched.")] public float blendInTime = 0.05f; [Tooltip("The time of blending out this script's effects when the puppet is not touched any more.")] public float blendOutTime = 1f; public bool enabled { get; private set; } public float mappingWeight { get; private set; } private float dam = 0f; private float damTime = -100f; private float damV; private float map, mapV; public void TryDamage(Collision collision, CollisionEventBroadcaster broadcaster) { bool included = false; for (int i = 0; i < indices.Length; i++) { if (broadcaster.muscle.index == indices[i]) { included = true; break; } } if (!included) return; damTime = Time.time; enabled = true; } public void Update(PuppetMasterLite puppetMaster) { if (!enabled) return; // Dynamically adjust drag, pin and mapping weights based on collisions so we can have perfect animation until there is a collision //dragW = Mathf.MoveTowards(dragW, 1f, Time.deltaTime * 2f); bool unpinned = puppetMaster.pinWeight <= 0f; float damTarget = Time.time > damTime + 0.2f ? 0f : 1f; if (unpinned) damTarget = 1f; float mapTarget = damTarget; if (unpinned) mapTarget = 1f; float sDampTime = damTarget > dam ? blendInTime : blendOutTime; dam = Mathf.SmoothDamp(dam, damTarget, ref damV, sDampTime); if (damTarget < dam && dam < 0.001f) dam = 0f; float mDampTime = mapTarget > map ? blendInTime : blendOutTime; map = Mathf.SmoothDamp(map, mapTarget, ref mapV, mDampTime); if (mapTarget < map && map < 0.001f) map = 0f; if (unpinned) dam = Mathf.Min(dam, map); float d = unpinned ? 0f : drag * map; float angularD = unpinned ? 0.05f : drag * map; mappingWeight = Mathf.Lerp(0f, 1f, map); for (int i = 0; i < indices.Length; i++) { int index = indices[i]; puppetMaster.muscles[index].pinWeightMlp = Mathf.Lerp(1f, pinWeightMlp, dam); puppetMaster.muscles[index].muscleWeightMlp = Mathf.Lerp(1f, muscleWeightMlp, dam); puppetMaster.muscles[index].rigidbody.drag = d; puppetMaster.muscles[index].rigidbody.angularDrag = angularD; //puppetMaster.muscles[index].mappingWeightMlp = mappingWeight; } if (dam <= 0f && map < 0f) enabled = false; } } public PuppetMasterLite puppetMaster; public LayerMask collisionLayers; [Tooltip("When the puppet is touched, sets pin weight and muscle weight values for these groups.")] public Group[] groups = new Group[0]; void Start() { foreach (MuscleLite m in puppetMaster.muscles) { var b = m.joint.gameObject.AddComponent(); b.listener = this; b.muscle = m; } } private bool NeedToUpdate() { foreach (Group group in groups) { if (group.enabled) return true; } return false; } void FixedUpdate() { if (!NeedToUpdate()) return; float maxMappingWeight = 0f; foreach (Group group in groups) { group.Update(puppetMaster); maxMappingWeight = Mathf.Max(maxMappingWeight, group.mappingWeight); } foreach (MuscleLite m in puppetMaster.muscles) { m.mappingWeightMlp = maxMappingWeight; } } // Called by CollisionEventBroadcaster when it collides with something public void OnCollisionEnterEvent(Collision collision, CollisionEventBroadcaster broadcaster) { ProcessCollisionEvent(collision, broadcaster); } public void OnCollisionStayEvent(Collision collision, CollisionEventBroadcaster broadcaster) { ProcessCollisionEvent(collision, broadcaster); } private void ProcessCollisionEvent(Collision collision, CollisionEventBroadcaster broadcaster) { if (collision.collider.transform.root == transform) return; if (!LayerMaskExtensions.Contains(collisionLayers, collision.collider.gameObject.layer)) return; foreach (Group group in groups) { group.TryDamage(collision, broadcaster); } } public void OnCollisionExitEvent(Collision collision, CollisionEventBroadcaster broadcaster) {} } }