TouchWalls.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using UnityEngine;
  2. using System.Collections;
  3. using RootMotion.FinalIK;
  4. namespace RootMotion.Demos {
  5. /// <summary>
  6. /// Demo script for using the Interaction System for touching scene geometry.
  7. /// </summary>
  8. public class TouchWalls : MonoBehaviour {
  9. /// <summary>
  10. /// Touching functionality for an effector
  11. /// </summary>
  12. [System.Serializable]
  13. public class EffectorLink {
  14. public bool enabled = true; // Can this effector start touching?
  15. public FullBodyBipedEffector effectorType; // The type of the effector
  16. public InteractionObject interactionObject; // The touch interaction object
  17. public Transform spherecastFrom; // The bone to start the sperecast from
  18. public float spherecastRadius = 0.1f; // The radius of sperecasting
  19. public float minDistance = 0.3f; // The minimum spherecast radius to touch
  20. public float distanceMlp = 1f; // Multiplies the distance of the spherecast
  21. public LayerMask touchLayers; // The layers to touch
  22. public float lerpSpeed = 10f; // The speed of lerping the interaction object
  23. public float minSwitchTime = 0.2f; // The minimum time to switch between touching
  24. public float releaseDistance= 0.4f; // The distance from the original touch point where the effector will lose contact
  25. public bool sliding; // Can the effector slide smoothly over the surfaces?
  26. private Vector3 raycastDirectionLocal;
  27. private float raycastDistance;
  28. private bool inTouch;
  29. private RaycastHit hit = new RaycastHit();
  30. private Vector3 targetPosition;
  31. private Quaternion targetRotation;
  32. private bool initiated;
  33. private float nextSwitchTime;
  34. private float speedF;
  35. // Initiate this instance
  36. public void Initiate(InteractionSystem interactionSystem) {
  37. // Find the direction to the interaction objet relative to the sperecastFrom Transform
  38. raycastDirectionLocal = spherecastFrom.InverseTransformDirection(interactionObject.transform.position - spherecastFrom.position);
  39. // Find the max distance the sperecast
  40. raycastDistance = Vector3.Distance(spherecastFrom.position, interactionObject.transform.position);
  41. // Add to the interaction system delegates
  42. interactionSystem.OnInteractionStart += OnInteractionStart;
  43. interactionSystem.OnInteractionResume += OnInteractionResume;
  44. interactionSystem.OnInteractionStop += OnInteractionStop;
  45. hit.normal = Vector3.forward;
  46. targetPosition = interactionObject.transform.position;
  47. targetRotation = interactionObject.transform.rotation;
  48. initiated = true;
  49. }
  50. // Spherecasting to find the walls
  51. private bool FindWalls(Vector3 direction) {
  52. if (!enabled) return false;
  53. bool found = Physics.SphereCast(spherecastFrom.position, spherecastRadius, direction, out hit, raycastDistance * distanceMlp, touchLayers);
  54. if (hit.distance < minDistance) found = false;
  55. return found;
  56. }
  57. // Update this instance
  58. public void Update(InteractionSystem interactionSystem) {
  59. if (!initiated) return;
  60. // The default position
  61. Vector3 direction = spherecastFrom.TransformDirection(raycastDirectionLocal);
  62. hit.point = spherecastFrom.position + direction;
  63. // Spherecasting
  64. bool wallFound = FindWalls(direction);
  65. // Starting and ending the interactions
  66. if (!inTouch) {
  67. if (wallFound && Time.time > nextSwitchTime) {
  68. interactionObject.transform.parent = null;
  69. interactionSystem.StartInteraction(effectorType, interactionObject, true);
  70. nextSwitchTime = Time.time + minSwitchTime / interactionSystem.speed;
  71. targetPosition = hit.point;
  72. targetRotation = Quaternion.LookRotation(-hit.normal);
  73. interactionObject.transform.position = targetPosition;
  74. interactionObject.transform.rotation = targetRotation;
  75. }
  76. } else {
  77. if (!wallFound) {
  78. // Resume if no wall found
  79. StopTouch(interactionSystem);
  80. } else {
  81. if (!interactionSystem.IsPaused(effectorType) || sliding) {
  82. targetPosition = hit.point;
  83. targetRotation = Quaternion.LookRotation(-hit.normal);
  84. }
  85. }
  86. if (Vector3.Distance(interactionObject.transform.position, hit.point) > releaseDistance) {
  87. if (wallFound) {
  88. targetPosition = hit.point;
  89. targetRotation = Quaternion.LookRotation(-hit.normal);
  90. } else {
  91. StopTouch(interactionSystem);
  92. }
  93. }
  94. }
  95. float speedFTarget = !inTouch || (interactionSystem.IsPaused(effectorType) && interactionObject.transform.position == targetPosition)? 0f: 1f;
  96. speedF = Mathf.Lerp(speedF, speedFTarget, Time.deltaTime * 3f * interactionSystem.speed);
  97. // Interpolating the interaction object
  98. float s = Time.deltaTime * lerpSpeed * speedF * interactionSystem.speed;
  99. interactionObject.transform.position = Vector3.Lerp(interactionObject.transform.position, targetPosition, s);
  100. interactionObject.transform.rotation = Quaternion.Slerp(interactionObject.transform.rotation, targetRotation, s);
  101. }
  102. // Stop touching the walls
  103. private void StopTouch(InteractionSystem interactionSystem) {
  104. interactionObject.transform.parent = interactionSystem.transform;
  105. nextSwitchTime = Time.time + minSwitchTime / interactionSystem.speed;
  106. if (interactionSystem.IsPaused(effectorType)) interactionSystem.ResumeInteraction(effectorType);
  107. else {
  108. speedF = 0f;
  109. targetPosition = hit.point;
  110. targetRotation = Quaternion.LookRotation(-hit.normal);
  111. }
  112. }
  113. // Called by the interaction system
  114. private void OnInteractionStart(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
  115. if (effectorType != this.effectorType || interactionObject != this.interactionObject) return;
  116. inTouch = true;
  117. }
  118. // Called by the interaction system
  119. private void OnInteractionResume(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
  120. if (effectorType != this.effectorType || interactionObject != this.interactionObject) return;
  121. inTouch = false;
  122. }
  123. // Called by the interaction system
  124. private void OnInteractionStop(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
  125. if (effectorType != this.effectorType || interactionObject != this.interactionObject) return;
  126. inTouch = false;
  127. }
  128. // Cleaning up the delegates
  129. public void Destroy(InteractionSystem interactionSystem) {
  130. if (!initiated) return;
  131. interactionSystem.OnInteractionStart -= OnInteractionStart;
  132. interactionSystem.OnInteractionResume -= OnInteractionResume;
  133. interactionSystem.OnInteractionStop -= OnInteractionStop;
  134. }
  135. }
  136. public InteractionSystem interactionSystem; // Reference to the interaciton sytem of the character
  137. public EffectorLink[] effectorLinks; // The wall touching effectors
  138. // Initiate the effector links
  139. void Start() {
  140. foreach (EffectorLink e in effectorLinks) e.Initiate(interactionSystem);
  141. }
  142. // Update touching
  143. void FixedUpdate() {
  144. for (int i = 0; i < effectorLinks.Length; i++) effectorLinks[i].Update(interactionSystem);
  145. }
  146. // Clean up the delegates
  147. void OnDestroy() {
  148. if (interactionSystem != null) {
  149. for (int i = 0; i < effectorLinks.Length; i++) effectorLinks[i].Destroy(interactionSystem);
  150. }
  151. }
  152. }
  153. }