MechSpider.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion.Demos {
  4. /// <summary>
  5. /// Mech spider Demo.
  6. /// </summary>
  7. public class MechSpider : MonoBehaviour {
  8. public LayerMask raycastLayers; // The ground layers
  9. public float scale = 1f; // For resizing the values when the mech is resized
  10. public Transform body; // The body transform, the root of the legs
  11. public MechSpiderLeg[] legs; // All the legs of this spider
  12. public float legRotationWeight = 1f; // The weight of rotating the body to each leg
  13. public float rootPositionSpeed = 5f; // The speed of positioning the root
  14. public float rootRotationSpeed = 30f; // The slerp speed of rotating the root to leg heights
  15. public float breatheSpeed = 2f; // Speed of the breathing cycle
  16. public float breatheMagnitude = 0.2f; // Magnitude of breathing
  17. public float height = 3.5f; // Height from ground
  18. public float minHeight = 2f; // The minimum height from ground
  19. public float raycastHeight = 10f; // The height of ray origin
  20. public float raycastDistance = 5f; // The distance of rays (total ray length = raycastHeight + raycastDistance)
  21. public Vector3 velocity { get; private set; }
  22. private Vector3 lastPosition;
  23. private Vector3 defaultBodyLocalPosition;
  24. private float sine;
  25. private RaycastHit rootHit;
  26. private void Start()
  27. {
  28. lastPosition = transform.position;
  29. }
  30. void Update() {
  31. velocity = (transform.position - lastPosition) / Time.deltaTime;
  32. lastPosition = transform.position;
  33. // Find the normal of the plane defined by leg positions
  34. Vector3 legsPlaneNormal = GetLegsPlaneNormal();
  35. // Rotating the root
  36. Quaternion fromTo = Quaternion.FromToRotation(transform.up, legsPlaneNormal);
  37. transform.rotation = Quaternion.Slerp(transform.rotation, fromTo * transform.rotation, Time.deltaTime * rootRotationSpeed);
  38. // Positioning the root
  39. Vector3 legCentroid = GetLegCentroid();
  40. Vector3 heightOffset = Vector3.Project((legCentroid + transform.up * height * scale) - transform.position, transform.up);
  41. transform.position += heightOffset * Time.deltaTime * (rootPositionSpeed * scale);
  42. if (Physics.Raycast(transform.position + transform.up * raycastHeight * scale, -transform.up, out rootHit, (raycastHeight * scale) + (raycastDistance * scale), raycastLayers)) {
  43. rootHit.distance -= (raycastHeight * scale) + (minHeight * scale);
  44. if (rootHit.distance < 0f) {
  45. Vector3 targetPosition = transform.position - transform.up * rootHit.distance;
  46. transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * rootPositionSpeed * scale);
  47. }
  48. }
  49. // Update Breathing
  50. sine += Time.deltaTime * breatheSpeed;
  51. if (sine >= Mathf.PI * 2f) sine -= Mathf.PI * 2f;
  52. float br = Mathf.Sin(sine) * breatheMagnitude * scale;
  53. // Apply breathing
  54. Vector3 breatheOffset = transform.up * br;
  55. body.transform.position = transform.position + breatheOffset;
  56. }
  57. // Calculate the normal of the plane defined by leg positions, so we know how to rotate the body
  58. private Vector3 GetLegCentroid() {
  59. Vector3 position = Vector3.zero;
  60. float footWeight = 1f / (float)legs.Length;
  61. // Go through all the legs, rotate the normal by it's offset
  62. for (int i = 0; i < legs.Length; i++) {
  63. position += legs[i].position * footWeight;
  64. }
  65. return position;
  66. }
  67. // Calculate the normal of the plane defined by leg positions, so we know how to rotate the body
  68. private Vector3 GetLegsPlaneNormal() {
  69. Vector3 normal = transform.up;
  70. if (legRotationWeight <= 0f) return normal;
  71. float legWeight = 1f / Mathf.Lerp(legs.Length, 1f, legRotationWeight);
  72. // Go through all the legs, rotate the normal by it's offset
  73. for (int i = 0; i < legs.Length; i++) {
  74. // Direction from the root to the leg
  75. Vector3 legDirection = legs[i].position - (transform.position - transform.up * height * scale);
  76. // Find the tangent to transform.up
  77. Vector3 legNormal = transform.up;
  78. Vector3 legTangent = legDirection;
  79. Vector3.OrthoNormalize(ref legNormal, ref legTangent);
  80. // Find the rotation offset from the tangent to the direction
  81. Quaternion fromTo = Quaternion.FromToRotation(legTangent, legDirection);
  82. fromTo = Quaternion.Lerp(Quaternion.identity, fromTo, legWeight);
  83. // Rotate the normal
  84. normal = fromTo * normal;
  85. }
  86. return normal;
  87. }
  88. }
  89. }